andriod拼凑wav声音文件

来源:互联网 发布:乌克兰 俄罗斯 知乎 编辑:程序博客网 时间:2024/06/05 00:39
    上一篇文章中介绍了,在windows的目录下,如何拼凑两个声音文件,下面来介绍一下在andriod中如何拼凑声音文件。    WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,该格式也支持MSADPCM,CCITT A LAW等多种压缩运算法,支持多种音频数字,取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相差无几! WAV打开工具是WINDOWS的媒体播放器。    通常使用三个参数来表示声音,量化位数,取样频率和采样点振幅。量化位数分为8位,16位,24位三种,声道有单声道和立体声之分,单声道振幅数据为n*1矩阵点,立体声为n*2矩阵点,取样频率一般有11025Hz(11kHz) ,22050Hz(22kHz)和44100Hz(44kHz) 三种,不过尽管音质出色,但在压缩后的文件体积过大!相对其他音频格式而言是一个缺点,其文件大小的计算方式为:WAV格式文件所占容量(B) = (取样频率 X量化位数X 声道) X 时间 / 8 (字节= 8bit) 每一分钟WAV格式的音频文件的大小为10MB,其大小不随音量大小及清晰度的变化而变化。    由于这里采集的音频相关参数一致,做我们去其中一段的头部作为拼接后的音频的头部。但是也不是这样就可以了。从上面WAV的格式中可以看出,头部中两个位置的数据需要修改。1、riff chunk中的size值;2、data chunk的size值。因此可以先将其他数据的data chunk部分的数据追加到结果文件中,最后写入这两个地方的值。
public class WavMergeUtil {    //inputs 为包含file对象的list    //output 为输出的目录文件。  public static void mergeWav(List<File> inputs, File output) throws IOException {    if (inputs.size() < 1) {      return;    }    FileInputStream fis = new FileInputStream(inputs.get(0));    FileOutputStream fos = new FileOutputStream(output);    byte[] buffer = new byte[2048];    int total = 0;    int count;    while ((count = fis.read(buffer)) > -1) {      fos.write(buffer, 0, count);      total += count;    }    fis.close();    for (int i = 1; i < inputs.size(); i++) {      File file = inputs.get(i);      Header header = resolveHeader(file);      FileInputStream dataInputStream = header.dataInputStream;      while ((count = dataInputStream.read(buffer)) > -1) {        fos.write(buffer, 0, count);        total += count;      }      dataInputStream.close();    }    fos.flush();    fos.close();    Header outputHeader = resolveHeader(output);    outputHeader.dataInputStream.close();    RandomAccessFile res = new RandomAccessFile(output, "rw");    res.seek(4);    byte[] fileLen = intToByteArray(total + outputHeader.dataOffset - 8);    res.write(fileLen, 0, 4);    res.seek(outputHeader.dataSizeOffset);    byte[] dataLen = intToByteArray(total);    res.write(dataLen, 0, 4);    res.close();  }  /**   * 解析头部,并获得文件指针指向数据开始位置的InputStreram,记得使用后需要关闭   */  private static Header resolveHeader(File wavFile) throws IOException {    FileInputStream fis = new FileInputStream(wavFile);    byte[] byte4 = new byte[4];    byte[] buffer = new byte[2048];    int readCount = 0;    Header header = new Header();    fis.read(byte4);//RIFF    fis.read(byte4);    readCount += 8;    header.fileSizeOffset = 4;    header.fileSize = byteArrayToInt(byte4);    fis.read(byte4);//WAVE    fis.read(byte4);//fmt    fis.read(byte4);    readCount += 12;    int fmtLen = byteArrayToInt(byte4);    fis.read(buffer, 0, fmtLen);    readCount += fmtLen;    fis.read(byte4);//data or fact    readCount += 4;    if (isFmt(byte4, 0)) {//包含fmt段      fis.read(byte4);      int factLen = byteArrayToInt(byte4);      fis.read(buffer, 0, factLen);      fis.read(byte4);//data      readCount += 8 + factLen;    }    fis.read(byte4);// data size    int dataLen = byteArrayToInt(byte4);    header.dataSize = dataLen;    header.dataSizeOffset = readCount;    readCount += 4;    header.dataOffset = readCount;    header.dataInputStream = fis;    return header;  }  private static boolean isRiff(byte[] bytes, int start) {    if (bytes[start + 0] == 'R' && bytes[start + 1] == 'I' && bytes[start + 2] == 'F' && bytes[start + 3] == 'F') {      return true;    } else {      return false;    }  }  private static boolean isFmt(byte[] bytes, int start) {    if (bytes[start + 0] == 'f' && bytes[start + 1] == 'm' && bytes[start + 2] == 't' && bytes[start + 3] == ' ') {      return true;    } else {      return false;    }  }  private static boolean isData(byte[] bytes, int start) {    if (bytes[start + 0] == 'd' && bytes[start + 1] == 'a' && bytes[start + 2] == 't' && bytes[start + 3] == 'a') {      return true;    } else {      return false;    }  }  /**   * 将int转化为byte[]   */  private static byte[] intToByteArray(int data) {    return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(data).array();  }  /**   * 将short转化为byte[]   */  private static byte[] shortToByteArray(short data) {    return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(data).array();  }  /**   * 将byte[]转化为short   */  private static short byteArrayToShort(byte[] b) {    return ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getShort();  }  /**   * 将byte[]转化为int   */  private static int byteArrayToInt(byte[] b) {    return ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getInt();  }  /**   * 头部部分信息   */  static class Header {    public int fileSize;    public int fileSizeOffset;    public int dataSize;    public int dataSizeOffset;    public int dataOffset;    public FileInputStream dataInputStream;  }}
下面介绍第二种拼凑的方法,见代码:
private static final byte RECORDER_BPP = 16;private static final long RECORDER_SAMPLERATE = 44100;private void CombineWaveFile(String file1, String file2) {    FileInputStream in1 = null, in2 = null;    FileOutputStream out = null;    long totalAudioLen = 0;    long totalDataLen = totalAudioLen + 36;    long longSampleRate = RECORDER_SAMPLERATE;    int channels = 2;    long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels / 8;    byte[] data = new byte[bufferSize];    try {        in1 = new FileInputStream(file1);        in2 = new FileInputStream(file2);        out = new FileOutputStream(getFilename3());        totalAudioLen = in1.getChannel().size() + in2.getChannel().size();        totalDataLen = totalAudioLen + 36;        WriteWaveFileHeader(out, totalAudioLen, totalDataLen,        longSampleRate, channels, byteRate);        while (in1.read(data) != -1) {            out.write(data);        }        while (in2.read(data) != -1) {            out.write(data);        }        out.close();        in1.close();        in2.close();    } catch (FileNotFoundException e) {        e.printStackTrace();    } catch (IOException e) {        e.printStackTrace();    }}private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,long totalDataLen, long longSampleRate, int channels, long byteRate)throws IOException {    byte[] header = new byte[44];    header[0] = 'R';    header[1] = 'I';    header[2] = 'F';    header[3] = 'F';    header[4] = (byte)(totalDataLen & 0xff);    header[5] = (byte)((totalDataLen >> 8) & 0xff);    header[6] = (byte)((totalDataLen >> 16) & 0xff);    header[7] = (byte)((totalDataLen >> 24) & 0xff);    header[8] = 'W';    header[9] = 'A';    header[10] = 'V';    header[11] = 'E';    header[12] = 'f';    header[13] = 'm';    header[14] = 't';    header[15] = ' ';    header[16] = 16;    header[17] = 0;    header[18] = 0;    header[19] = 0;    header[20] = 1;    header[21] = 0;    header[22] = (byte) channels;    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);    header[33] = 0;    header[34] = RECORDER_BPP;    header[35] = 0;    header[36] = 'd';    header[37] = 'a';    header[38] = 't';    header[39] = 'a';    header[40] = (byte)(totalAudioLen & 0xff);    header[41] = (byte)((totalAudioLen >> 8) & 0xff);    header[42] = (byte)((totalAudioLen >> 16) & 0xff);    header[43] = (byte)((totalAudioLen >> 24) & 0xff);    out.write(header, 0, 44);}
敲代码写文章真的挺不容易的,请各位兄弟姐妹们不要直接copy之后就搞成自己的,谢谢。