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

使用Java混音器混合两个音频流,java,audio,javasound,Java,Audio,Javasound,我想使用java混音器混合两个音频流,并将输出写入文件 为此,我通过读取麦克风混音器的TargetDataLines来捕获两个麦克风的输入: //microphone TargetDataLines TargetDataLine finalIn = null; TargetDataLine finalIn2 = null; Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo(); for (Mixer.I

我想使用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);
从麦克风捕获的结果数据将位于
targetData
targetData2
中。现在,我想将包含从麦克风接收的声音样本的这两个字节数组混合到一个新的字节数组中,我想使用另一个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混音器的功能有误解。我认为这门课的名字不好,因为我是一名音频工程师。在我看来,混音器是将各种音轨组合在一起的地方。这不是Java混合器所做的

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

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

// Here, do something useful with the audio data that's 
// now in the audioBytes array...
本例从AudioInputStream读取,但从TargetDataLines获取单个字节的技术并没有那么不同。当然,您将从两行而不是从单个AI读取。您将要做的“有用的事情”是在每帧的基础上并行地添加PCM数据


一旦你对音频数据进行了汇总,你就可以在另一个站点上使用和发布,该站点接收PCM流并将其作为wav文件输出。希望这一页上的讨论足够清晰,您可以理解。

我想知道您是否对Java混音器的功能有误解。我认为这门课的名字不好,因为我是一名音频工程师。在我看来,混音器是将各种音轨组合在一起的地方。这不是Java混合器所做的

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

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

// Here, do something useful with the audio data that's 
// now in the audioBytes array...
本例从AudioInputStream读取,但从TargetDataLines获取单个字节的技术并没有那么不同。当然,您将从两行而不是从单个AI读取。您将要做的“有用的事情”是在每帧的基础上并行地添加PCM数据


一旦你对音频数据进行了汇总,你就可以在另一个站点上使用和发布,该站点接收PCM流并将其作为wav文件输出。希望该页面上的讨论足够清晰,您可以跟随。

您想存储结果还是播放结果?如果你玩它,你有另一张声卡吗?目标行是捕获而不是写入,因此结果不会被存储;你需要明确你到底想做什么;你有很多声卡吗??如果你想尽快得到更好的帮助,请发布一个or。我的两个网络摄像头和一个声卡上有两个麦克风。我需要从我的程序中捕捉到发送给扬声器的信号。我想捕捉与该混音器相关的目标线。我完全不理解其原理:你想混合两个输入;但混合器将进行混合;你为什么不让声音通过并捕捉混音器;这是一项无用的任务,或是助长黑客行为的东西;我不明白你想要达到什么-你想储存结果还是玩它?如果你玩它,你有另一张声卡吗?目标行是捕获而不是写入,因此结果不会被存储;你需要明确你到底想做什么;你有很多声卡吗??如果你想尽快得到更好的帮助,请发布一个or。我的两个网络摄像头和一个声卡上有两个麦克风。我需要从我的程序中捕捉到发送给扬声器的信号。我想捕捉与该混音器相关的目标线。我完全不理解其原理:你想混合两个输入;但混合器将进行混合;你为什么不让声音通过并捕捉混音器;这是一项无用的任务,或是助长黑客行为的东西;我不明白你想要实现什么——这很有启发性。我设法使用您提供的链接编写了一个简单的混音器。然而,我想知道我是否可以从Java访问一个硬件混音器来为我做音频混音。似乎是有道理的,但我从来没有做过。我计划在下个月为我编写的JavaSynth编写MIDI输入读取功能代码。这将是我第一次尝试处理默认SourceDataLine和TargetDataLine以外的行。这非常有启发性。我设法使用您提供的链接编写了一个简单的混音器。然而,我想知道我是否可以从Java访问一个硬件混音器来为我做音频混音。似乎是有道理的,但我从来没有做过。我计划在下个月为我编写的JavaSynth编写MIDI输入读取功能代码。这将是我第一次尝试处理默认SourceDataLine和TargetDataLine以外的行。