音频文件合并(MAV格式)

 

说明

  1. 读取文件头

    • 使用 readHeader 方法读取前 44 字节的文件头。(不同格式文件头不同)
  2. 读取数据部分

    • 使用 readData 方法逐段读取数据部分,并将其写入 ByteArrayOutputStream
  3. 检查文件头一致性

    • 使用 areHeadersEqual 方法检查所有 WAV 文件的格式是否一致。
  4. 更新文件头

    • 使用 updateWavHeader 方法更新文件头中的数据长度信息。
    • 使用 intToByteArray 方法将整数转换为字节数组,以便更新文件头。
  5. 写入合并后的文件

    • 将所有 WAV 文件的内容写入到输出文件中。

注意事项

  1. 文件头一致性

    • 确保所有 WAV 文件的格式完全一致,包括采样率、通道数、位深度等。
  2. 数据长度更新

    • 在合并完成后,更新文件头中的数据长度信息,以确保新的 WAV 文件是有效的。
  3. 输入流读取

    • 使用逐段读取的方式确保完整地读取整个文件内容。

代码

package com.kjhd.note.controller;

import java.io.*;
import java.util.List;

public class WavMerger {

    public static void main(String[] args) {
        List<InputStream> inputStreams = List.of(
            new FileInputStream("1.wav"),
            new FileInputStream("2.wav")
        );
        File outputFile = new File("merged.wav");

        try {
            mergeWavFiles(inputStreams, outputFile);
            System.out.println("WAV 文件合并成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void mergeWavFiles(List<InputStream> inputStreams, File outputFile) throws IOException {
        try (RandomAccessFile output = new RandomAccessFile(outputFile, "rw")) {
            // 读取第一个 WAV 文件的全部内容
            InputStream firstInput = inputStreams.get(0);
            byte[] header1 = readHeader(firstInput);
            byte[] data1 = readData(firstInput);

            // 检查其他 WAV 文件的格式是否与第一个一致
            byte[] header = header1;
            int totalDataLength = data1.length;
            for (int i = 1; i < inputStreams.size(); i++) {
                InputStream input = inputStreams.get(i);
                byte[] currentHeader = readHeader(input);
                byte[] currentData = readData(input);

                if (!areHeadersEqual(header, currentHeader)) {
                    throw new IOException("WAV 文件的格式不一致");
                }

                // 更新总数据长度
                totalDataLength += currentData.length;
            }

            // 更新文件头中的数据长度
            updateWavHeader(header, totalDataLength);

            // 写入所有文件的内容
            output.write(header);
            for (InputStream input : inputStreams) {
                byte[] data = readData(input);
                output.write(data);
            }
        }
    }

    private static byte[] readHeader(InputStream in) throws IOException {
        byte[] header = new byte[44];
        int bytesRead = in.read(header);
        if (bytesRead != header.length) {
            throw new IOException("无法读取完整的 WAV 文件头");
        }
        return header;
    }

    private static byte[] readData(InputStream in) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1) {
            baos.write(buffer, 0, bytesRead);
        }
        return baos.toByteArray();
    }

    private static boolean areHeadersEqual(byte[] header1, byte[] header2) {
        // 检查文件头的主要部分(比如采样率、位深度等)是否一致
        return Arrays.equals(Arrays.copyOfRange(header1, 0, 4), Arrays.copyOfRange(header2, 0, 4)) &&
               Arrays.equals(Arrays.copyOfRange(header1, 8, 12), Arrays.copyOfRange(header2, 8, 12)) &&
               Arrays.equals(Arrays.copyOfRange(header1, 20, 22), Arrays.copyOfRange(header2, 20, 22)) &&
               Arrays.equals(Arrays.copyOfRange(header1, 22, 24), Arrays.copyOfRange(header2, 22, 24)) &&
               Arrays.equals(Arrays.copyOfRange(header1, 24, 28), Arrays.copyOfRange(header2, 24, 28)) &&
               Arrays.equals(Arrays.copyOfRange(header1, 34, 36), Arrays.copyOfRange(header2, 34, 36));
    }

    private static void updateWavHeader(byte[] header, int totalDataLength) {
        // 更新 RIFF 区块的大小(文件长度 - 8)
        int riffChunkSizeOffset = 4;
        int riffChunkSize = 44 + totalDataLength - 8;
        byte[] riffChunkSizeBytes = intToByteArray(riffChunkSize);
        System.arraycopy(riffChunkSizeBytes, 0, header, riffChunkSizeOffset, 4);

        // 更新 数据区块的大小
        int dataChunkSizeOffset = 40;
        byte[] dataChunkSizeBytes = intToByteArray(totalDataLength);
        System.arraycopy(dataChunkSizeBytes, 0, header, dataChunkSizeOffset, 4);
    }

    private static byte[] intToByteArray(int value) {
        return new byte[] {
            (byte) (value & 0xFF),
            (byte) ((value >> 8) & 0xFF),
            (byte) ((value >> 16) & 0xFF),
            (byte) ((value >> 24) & 0xFF)
        };
    }
}

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值