使用Java混音器

时间:2016-06-17 22:21:22

标签: java audio javasound

我想使用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);
    }

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

1 个答案:

答案 0 :(得分:1)

我想知道你是否对Java Mixer的作用有误解。由于我作为音频工程师的背景经验,我认为这门课的名字很差。在我看来,混音器是你组合各种音轨的地方。这是 Java Mixer的功能。

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

有一个很好的教程,展示了如何获得单个字节/帧here。在页面的下方,有一个代码示例。注意评论的位置:

Private Sub Test()
    Using strm As Stream = File.Open("Textfile.zip", FileMode.Open)
        ListZipEntries(strm)
    End Using
End Sub

Private Sub ListZipEntries(strm As Stream)
    Using archive As New ZipArchive(strm, ZipArchiveMode.Read, False)   ' closes stream when done
        For Each entry As ZipArchiveEntry In archive.Entries

            Debug.Print(entry.FullName)
            Dim fi As New FileInfo(entry.FullName)

            If String.Equals(fi.Extension, ".zip", StringComparison.InvariantCultureIgnoreCase) Then
                Debug.IndentLevel += 1
                Using entryStream As Stream = entry.Open()
                    ListZipEntries(entryStream)
                End Using
                Debug.IndentLevel -= 1
            End If
        Next
    End Using
End Sub

此示例从AudioInputStream读取,但从TargetDataLines获取单个字节的技术并没有那么不同。当然,您将从两条线而不是单一AIS读取。 "有用的东西"你要做的只是在每帧的基础上并行添加PCM数据。

一旦你得到音频数据的总和,你可以使用some code I wrote并在另一个站点发布,它接收PCM流并将其作为wav文件写出来。希望在该页面上的讨论足够明确,您可以关注。