如何在java中将Wav文件拆分为通道?

Posted

技术标签:

【中文标题】如何在java中将Wav文件拆分为通道?【英文标题】:How to split a Wav file into channels in java? 【发布时间】:2011-04-23 19:40:09 【问题描述】:

我想编写一个 Java 程序来将 wav 文件拆分为通道。输入将是一个 wav 文件,输出将是与频道一样多的 wav 文件。我可以在 Java 中读取 wav 文件,但是如何将其拆分为通道?

【问题讨论】:

【参考方案1】:

Wave 标头包含每个样本的样本大小(以位为单位)字段以及在波形文件中编码的通道数。

有了这些信息,您就可以拆分通道:波形文件中的样本数据包含交错的每个通道的样本。

即如果您有两个通道(A,B),您有 sA1、sB1、sA2、SB2、sA3、sB3 - 首先是 A 的样本,然后是 B 的样本,然后是 A 的样本,依此类推。这意味着如果您有样本大小,即 16 位,您从属于通道 A 的文件中读取 2 个字节,然后是属于通道 B 的 2 个字节,依此类推。

【讨论】:

你如何从样本中读取 2 个字节?你能写一个例子吗?【参考方案2】:

如果您有 16 位深度,这意味着每个样本将占用 2 个字节。这意味着左声道数据将以字节 0,1、4,5... 等为单位。

在我的项目中,我使用 AudioRecord 从两个内置麦克风录制立体声。

private int audiosource = MediaRecorder.AudioSource.MIC;   
private static int sampleRateInHz = 44100;  
private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;  
private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;  

readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);   
for(int i = 0; i < readsize/2; i = i + 2)


      leftChannelAudioData[i] = audiodata[2*i];
      leftChannelAudioData[i+1] = audiodata[2*i+1]; 
      rightChannelAudioData[i] =  audiodata[2*i+2];
      rightChannelAudioData[i+1] = audiodata[2*i+3];

然后我从立体声中得到了两个声道。

希望这会有所帮助!

【讨论】:

问题是针对 Java 而不是 android。问题标签也不表示任何 Android 除了输入法,答案是纯Java。只需替换从 AudioInputStream 读取字节数组即可。【参考方案3】:

这是一个完整的例子:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

public class ChannelSplitter 

    public static void main(String[] args) throws Exception 

        String filename = "test.wav";

        File sourceFile = new File(filename);
        File leftTargetFile = new File("left_"+filename);
        File rightTargetFile = new File("right_"+filename);

        AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(sourceFile);
        AudioFileFormat.Type targetFileType = fileFormat.getType();
        AudioFormat audioFormat = fileFormat.getFormat();

        AudioInputStream inputAIS = AudioSystem.getAudioInputStream(sourceFile);

        ByteArrayOutputStream leftbaos = new ByteArrayOutputStream();
        ByteArrayOutputStream rightbaos = new ByteArrayOutputStream();

        byte[] bytes = new byte[(audioFormat.getSampleSizeInBits()/8)*2];

        while (true) 

            int readsize = inputAIS.read(bytes);   

            if(readsize==-1)
                break;
            

            rightbaos.write(bytes,0,bytes.length/2);
            leftbaos.write(bytes,bytes.length/2,bytes.length/2);
        

        byte[] leftData = leftbaos.toByteArray();
        byte[] rightData = rightbaos.toByteArray();

        AudioFormat outFormat = new AudioFormat(audioFormat.getEncoding(),audioFormat.getSampleRate(),audioFormat.getSampleSizeInBits(),1,audioFormat.getFrameSize()/2, audioFormat.getFrameRate(),audioFormat.isBigEndian());

        ByteArrayInputStream leftbais = new ByteArrayInputStream(leftData);
        AudioInputStream leftoutputAIS = new AudioInputStream(leftbais, outFormat, leftData.length / outFormat.getFrameSize());
        AudioSystem.write(leftoutputAIS, targetFileType, leftTargetFile);

        ByteArrayInputStream rightbais = new ByteArrayInputStream(rightData);
        AudioInputStream rightoutputAIS = new AudioInputStream(rightbais, outFormat, rightData.length / outFormat.getFrameSize());
        AudioSystem.write(rightoutputAIS, targetFileType, rightTargetFile);
    

【讨论】:

我看不出这个答案在原始立体声线路中的两个通道之间有什么区别。【参考方案4】:

找到了一种非常简单的方法,但不确定它的计算效率如何......

public void splitByteArray (byte [] fileContent, byte [] fileContentLeft, byte [] fileContentRight) 
    for (int i = 0; i < fileContent.length; i += 4) 
        fileContentLeft[i] = fileContent[i];
        fileContentLeft[i + 1] = fileContent[i + 1];
        fileContentRight[i + 2] = fileContent[i + 2];
        fileContentRight[i + 3] = fileContent[i + 3];
    

这适用于 16 位 wav PCM,其中立体声阵列中的 0 和 1 索引是左声道,2 和 3 是右声道(均为 8 位单声道)。

【讨论】:

这两个结果数组保留了 16 位编码状态。

以上是关于如何在java中将Wav文件拆分为通道?的主要内容,如果未能解决你的问题,请参考以下文章

gstreamer 将多通道 wav 文件拆分为单独的通道并将每个通道编码为 mp3、alac 等并保存到文件

将 G.723.1 转换为普通 wav 和拆分通道?

如何在 HTML 中将 CSD 文件渲染为 WAV

如何以编程方式在 Android 中将 .mid 转换为 .wav 文件?

如何在 Silverlight 应用程序中将 byte[] 保存为 wav 文件?

如何使用流体合成器将单个 midi 通道导出为 wav?