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

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

【问题讨论】:

    标签: java audio 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 位编码状态。
    猜你喜欢
    • 1970-01-01
    • 2016-10-26
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-21
    相关资源
    最近更新 更多