使用 Java 混合器混合两个音频流

Mixing two streams of audio using Java mixer

我想使用 java 混合器混合两个音频流,并将输出写入文件。

为此,我通过读取我的麦克风混音器的 TargetDataLines 来捕获我的两个麦克风的输入:

    //microphone TargetDataLines
    TargetDataLine finalIn = null;
    TargetDataLine finalIn2 = null;

    Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
    for (Mixer.Info info: mixerInfos){

        Mixer m = AudioSystem.getMixer(info);
        Line.Info[] lineInfos = m.getSourceLineInfo();
        System.out.println("****mixer name:" + info.getName());
        if(info.getName().equals("C920 [plughw:1,0]"))
            finalIn=(TargetDataLine) m.getLine(m.getTargetLineInfo()[0]);
        if(info.getName().equals("C920_1 [plughw:3,0]"))
            finalIn2=(TargetDataLine) m.getLine(m.getTargetLineInfo()[0]);

        for (Line.Info lineInfo:lineInfos){
            System.out.println ("\n source line info: "+lineInfo);
        }
        lineInfos = m.getTargetLineInfo();
        for (Line.Info lineInfo:lineInfos){
            System.out.println ("target line info: "+lineInfo);
        }

    }

    AudioFormat format = new AudioFormat(8000,16, 1, true,false);

    finalIn.open(format,2000);
    finalIn.start();
    finalIn2.open(format,2000);
    finalIn2.start();

    int numBytesRead;
    byte[] targetData = new byte[finalIn.getBufferSize() / 5];

    int numBytesRead2;
    byte[] targetData2 = new byte[finalIn2.getBufferSize() / 5];

    while (true) {
            numBytesRead = finalIn.read(targetData,0,targetData.length);
            numBytesRead2 = finalIn2.read(targetData2, 0, targetData2.length);

从麦克风捕获的结果数据将在 targetDatatargetData2 中。现在我想将这两个包含我从麦克风接收到的声音样本的字节数组混合到一个新的字节数组中 我想为此使用另一个 Java 混音器 .

为此,我使用以下代码创建了两条 SourceDataLine 和一条 TargetDataLine:

        DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, format);
        DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format);
        SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(sourceInfo);
        SourceDataLine sourceLine2 = (SourceDataLine) AudioSystem.getLine(sourceInfo);

        sourceLine.open(format,2000);
        sourceLine.start();

        sourceLine2.open(format,2000);
        sourceLine2.start();

        TargetDataLine targetLine = (TargetDataLine)        AudioSystem.getLine(targetInfo);
        targetLine.open(format,2000);
        targetLine.start();

然后在 "while" 中添加:

    byte[] result = new byte[finalIn.getBufferSize() / 5];

    while (true) {
            numBytesRead = finalIn.read(targetData,0,targetData.length);
            numBytesRead2 = finalIn2.read(targetData2, 0, targetData2.length);

            sourceLine.write(targetData, 0, numBytesRead);
            sourceLine.write(targetData2, 0, numBytesRead2);
            targetLine.read(result, 0, numBytesRead2);
    }

然而,虽然声音实际上通过我的耳机正常播放,但结果数组仍然是空的。 我怎么解决这个问题?我做错了什么?

我想知道您是否对 Java 混音器的作用有误解。我认为这个 class 命名不当,因为我作为音频工程师的背景经验。在我看来,混音器就是组合各种音轨的地方。 不是Java混音器的作用。

我想做你想做的事,你需要并行阅读你的两行。对于每个,您将读取字节缓冲区,并且必须将字节转换为 PCM 数据。然后,您可以将 PCM 数据加在一起并将其转换回字节并输出。

有一个很好的教程展示了如何针对个人 bytes/frames here。在页面的下方,有一个代码示例。注意评论位置:

// Here, do something useful with the audio data that's 
// now in the audioBytes array...

此示例从 AudioInputStream 读取,但从 TargetDataLines 获取单个字节的技术并没有太大不同。当然,您会从两行读取而不是从单个 AIS 读取。 "useful thing" 您要做的只是在每帧的基础上并行添加 PCM 数据。

汇总音频数据后,您可以使用 some code I wrote 并发布到另一个站点,该站点采用 PCM 流并将其写为 wav 文件。希望该页面上的讨论足够清楚,您可以跟进。