混合波形文件

Posted

技术标签:

【中文标题】混合波形文件【英文标题】:Mixing wave files 【发布时间】:2017-06-09 13:01:59 【问题描述】:

我不能混合两个音频扩展文件 wav。我的作品:

byte[] bufData1 = null;
byte[] bufData2 = null;
ArrayList<Byte> bufData3 = new ArrayList<Byte>();

使用原始音频数据创建两个数组

 public void bootloadInputData(String p1, String p2) throws IOException 
        bufData1 = bootloadReadFileByte(p1);
        bufData2 = bootloadReadFileByte(p2);
        System.arraycopy(bufData1, 44, bufData1, 0, (bufData1.length - 44));
        System.arraycopy(bufData2, 44, bufData2, 0, (bufData2.length - 44));
 

 public byte[] bootloadReadFileByte(String path) throws IOException
    ByteArrayOutputStream out = null;
    InputStream input = null;
    try
        out = new ByteArrayOutputStream();
        input = new BufferedInputStream(new FileInputStream(path));
        int data = 0;
        while((data = input.read()) != -1)
            out.write(data);
        
    
    finally
        if(null != input)
            input.close();
        
        if(null != out)
            out.close();
        
    
    return out.toByteArray();

混合原始音频数据的字节

public void bootloadOutputData() throws IOException 
        for(int i = 0; i < ((bufData1.length + bufData2.length) / 4); i += 4) 
            if(i < bufData1.length)
                bufData3.add(bufData1[i]);
                bufData3.add(bufData1[i+1]);
                bufData3.add(bufData1[i+2]);
                bufData3.add(bufData1[i+3]);
            
            if(i < bufData2.length)
                bufData3.add(bufData2[i]);
                bufData3.add(bufData2[i+1]);
                bufData3.add(bufData2[i+2]);
                bufData3.add(bufData2[i+3]);
            
        
    

新建一个文件,填入文件头和原始音频数据。

private void bootloadCreateWaveMix(String p1, String p2, String p3) throws IOException 
    int size1 = 0;
    int size2 = 0;

    FileInputStream fis1 = null;
    FileInputStream fis2 = null;
    try 
        fis1 = new FileInputStream(p1);
        fis2 = new FileInputStream(p2);
        size1 = fis1.available();
        size2 = fis2.available();
     finally 
        if(fis1 != null)
            fis1.close();
        
        if(fis2 != null)
            fis2.close();
        
    

    int mNumBytes = (size1 + size2);

    DataOutputStream out = null;
    try 
        out = new DataOutputStream(new FileOutputStream(p3));
        writeId(out, "RIFF");
        writeInt(out, 36 + mNumBytes);
        writeId(out, "WAVE");

        writeId(out, "fmt ");
        writeInt(out, 16);
        writeShort(out, (short) 1);
        writeShort(out, (short) 4);
        writeInt(out, (int) 44100);
        writeInt(out, 2 * 44100 * 16 / 8);
        writeShort(out, (short)(2 * 16 / 8));
        writeShort(out, (short) 16);

        writeId(out, "data");
        writeInt(out, mNumBytes);

        out.write(toByteArray(bufData3));
     finally 
        if(out != null)
            out.close();
        
    


private static void writeId(OutputStream out, String id) throws IOException 
    for (int i = 0; i < id.length(); i++) out.write(id.charAt(i));


private static void writeInt(OutputStream out, int val) throws IOException 
    out.write(val >> 0);
    out.write(val >> 8);
    out.write(val >> 16);
    out.write(val >> 24);


private static void writeShort(OutputStream out, short val) throws IOException 
    out.write(val >> 0);
    out.write(val >> 8);


public static byte[] toByteArray(ArrayList<Byte> in) 
    byte[] data = new byte[in.size()];
    for (int i = 0; i < data.length; i++) 
        data[i] = (byte) in.get(i);
    
    return data;

问题:

此代码未正确创建计算机无法创建的文件 玩,但设备可以。复制不好,有种 合并文件末尾的干扰。此外,播放结束时 第一个文件结束,即使第二个文件比第一个大 一。这个想法的通道的另一个问题是两个立体声 文件,在标题中我指出 4 生命,即使 2。文件 将始终为 44100/16 位/立体声

【问题讨论】:

混合意味着您希望最终得到一个音频文件文件,该文件是两个信号的总和。它最终应该是相同数量的通道,两个文件中较长的长度。您在 bootloadOutputData 中所做的实际上似乎是两个音频文件的“交错”样本。我期望的是 1) 将每个样本转换为 int 或 float。 2)将它们加在一起 ​​3)将该结果转换为字节,并将其写入您的输出 作为将多个音轨混合在一起的垫脚石是让代码工作,该代码在一个音轨中读取,向下挖掘到您可以访问音频曲线字节的 PCM 原始音频级别...将它们打印到控制台当您阅读输入文件时,然后将该低级原始音频保存到输出文件中......一旦您开始工作,并行执行多个轨道会容易得多 也使用单声道音频而不是立体声,因为立体声增加了您以后可以轻松添加的复杂性...免费音频工作站 Audacity 是您的朋友,可以在那里可视化音频,直到您编写自己的音频代码工具箱实用程序来执行类似操作;-) @Ehz。事实证明,我还需要解析段落上的每个文件以及要翻译的每个新段落 (int) 并对每个 int countParagraphs[] = new int[count]; countParagraphs[0] = (c1 + c2); //... 求和,最后将所有要 int 的值转换为字节并写入原始数据? @ScottStensland。谢谢回复。您能详细说明一下曲目吗? 【参考方案1】:

如果我理解正确,您希望执行以下操作:

    给定 2 个输入 WAV 文件,将它们混合成一个 WAV 文件。 输出的内容将是同时播放的输入文件,而不是一个接一个。 新文件的长度将是输入文件中最长的长度。 所有文件(输入和输出)均为 16 位、立体声 44100Hz。

如果是这样,以下是您的(部分)错误:

    您需要解析传入的文件,这样您就不会将它们的标题读取为音频数据(不要因为您已经知道音频的格式而跳过此步骤。您需要读取标题以确认数据格式并准确确定输入中的样本数量。另外,请注意,2/16/44100 WAV 文件可以有不同大小的标题,因为它们可以包含各种块,所以你不能跳过 X 字节然后读取文件 - - 您必须解析标题!)。 如果 WAV 文件都是 16 位的,则需要将传入的数据从字节转换为 short(注意,这不是简单的类型转换——您必须将 2 个字节打包成每个 short。我相信您可以使用DataInputStream 为此,但一定要考虑字节序——WAV 文件是小端,Java 是大端)。一旦你得到了代表你的样本的短裤,平均来自不同文件的短裤进行混合。然后,您的平均值必须转换回字节 (DataOutputStream) 以保存结果文件。当您用完一个文件中的数据时,请替换为零。 您对 numBytes 的计算不正确 - 它不是两个文件中原始字节的总和,而是稍微复杂一些的计算。在您的情况下,您希望它等于以下内容:
 n1 = number of samples in file 1
 n2 = number of samples in file 2
 n = MAX( n1 + n2 )
 numBytes = n * (number of channels) * (number of bytes per channel) = n * 2 * 2

我强烈建议您考虑使用 JMF 之类的库来处理 1 和 2。

【讨论】:

此库适用于 android Studio (Windows x64)?找不到,求链接下载? oracle.com/technetwork/java/javase/download-142937.html 也许不适用于 Android,IDK。 Android 原生支持 WAV 文件:developer.android.com/guide/topics/media/media-formats.html

以上是关于混合波形文件的主要内容,如果未能解决你的问题,请参考以下文章

数字化仪与任意波形发生器的混合模式选项现已开启

FPGA-vivado仿真导出波形文件

vivodo仿真文件出现在nonmodule files仿真波形全是红色和蓝色线,怎么办?

在波形上显示波形文件播放进度的最佳方式

从流中播放波形文件

在 Python 中读取波形文件