检查调音台线路中的音频播放级别?

Zac*_*aro 6 java

我试图弄清楚Windows中是否播放任何类型的声音(通过任何应用程序).如果有什么东西在某处发出声音,我想知道它!

按照文档后,我已经找到了如何获得机器上的混音器列表,以及这些混音器的行 - 如果我理解正确的话,那就是混音器的输入/输出.

但是,我遇到的问题是我不知道如何从线路获取所需的数据.

我看到的唯一具有音量级概念的界面是DataLine.这个问题是我无法弄清楚什么返回实现数据线接口的对象.

列举所有混音器和线路:

public static void printMixers() {
    Mixer.Info[] mixers = AudioSystem.getMixerInfo();
    for (Mixer.Info mixerInfo : mixers) {
        Mixer mixer = AudioSystem.getMixer(mixerInfo);
        try {
            mixer.open();
            Line.Info[] lines = mixer.getSourceLineInfo();
            for (Line.Info linfo : lines) {
                System.out.println(linfo);
            }
        } 
        catch (LineUnavailableException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
Run Code Online (Sandbox Code Playgroud)

该代码枚举并显示我机器上的所有音频设备.从那,其中一个不应该Lines包含某种播放级数据?

Sky*_*ion 6

哦,你想找到音量?好吧,并非所有硬件都支持它,但这里是你如何获得数据线.

    public static SourceDataLine getSourceDataLine(Line.Info lineInfo){
    try{
        return (SourceDataLine) AudioSystem.getLine(lineInfo);
    }
    catch(Exception ex){
        ex.printStackTrace();
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后只需调用SourceDataLine.getLevel()来获取卷.我希望这有帮助.

注意:如果声音来自JVM之外或不通过JavaSound API,则此方法将无法检测到声音,因为JVM无法访问与SourceDataLine等效的操作系统.

更新:经过进一步研究,大多数系统都没有实现getLevel().所以我根据这个论坛讨论手动实现了这个方法:https://community.oracle.com/message/5391003

以下是课程:

public class Main {

    public static void main(String[] args){
        MicrophoneAnalyzer mic = new MicrophoneAnalyzer(FLACFileWriter.FLAC);
        System.out.println("HELLO");
        mic.open();
        while(true){
            byte[] buffer = new byte[mic.getTargetDataLine().getFormat().getFrameSize()];
            mic.getTargetDataLine().read(buffer, 0, buffer.length);
            try{
                System.out.println(getLevel(mic.getAudioFormat(), buffer));
            }
            catch(Exception e){
                System.out.println("ERROR");
                e.printStackTrace();
            }
        }
    }

    public static double getLevel(AudioFormat af, byte[] chunk) throws IOException{
        PCMSigned8Bit converter = new PCMSigned8Bit(af);
        if(chunk.length != converter.getRequiredChunkByteSize())
            return -1;

        AudioInputStream ais = converter.convert(chunk);
        ais.read(chunk, 0, chunk.length);

        long lSum = 0;
        for(int i=0; i<chunk.length; i++)
            lSum = lSum + chunk[i];

        double dAvg = lSum / chunk.length;
        double sumMeanSquare = 0d;

        for(int j=0; j<chunk.length; j++)

            sumMeanSquare = sumMeanSquare + Math.pow(chunk[j] - dAvg, 2d);

        double averageMeanSquare = sumMeanSquare / chunk.length;

        return (Math.pow(averageMeanSquare,0.5d));
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用的方法仅适用于8bitPCM,因此我们必须将编码转换为使用这两个类的编码.这是一般的抽象转换器类.

import java.io.ByteArrayInputStream;
import java.io.IOException;

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

abstract class AbstractSignedLevelConverter
{
    private AudioFormat srcf;

    public AbstractSignedLevelConverter(AudioFormat sourceFormat)
    {
        srcf = sourceFormat;
    }


    protected AudioInputStream convert(byte[] chunk)
    {
        AudioInputStream ais = null;
        if(AudioSystem.isConversionSupported(   AudioFormat.Encoding.PCM_SIGNED,
                                                            srcf))
        {
            if(srcf.getEncoding() != AudioFormat.Encoding.PCM_SIGNED)
                ais = AudioSystem.getAudioInputStream(
                        AudioFormat.Encoding.PCM_SIGNED,
                        new AudioInputStream(new ByteArrayInputStream(chunk),
                                                    srcf,
                                                    chunk.length * srcf.getFrameSize()));
            else
                ais = new AudioInputStream(new ByteArrayInputStream(chunk),
                                                    srcf,
                                                    chunk.length * srcf.getFrameSize());
        }

        return ais;
    }

    abstract public double convertToLevel(byte[] chunk)  throws IOException;

    public int getRequiredChunkByteSize()
    {
        return srcf.getFrameSize();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是8BitPCM的一个

import java.io.IOException;

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

public class PCMSigned8Bit extends AbstractSignedLevelConverter
{
    PCMSigned8Bit(AudioFormat sourceFormat)
    {
        super(sourceFormat);
    }

    public double convertToLevel(byte[] chunk) throws IOException
    {
        if(chunk.length != getRequiredChunkByteSize())
            return -1;

        AudioInputStream ais = convert(chunk);
        ais.read(chunk, 0, chunk.length);

        return (double)chunk[0];
    }




}
Run Code Online (Sandbox Code Playgroud)

这适用于TargetDataLine,它可能在您的用例中不起作用,但您可以围绕SourceDataLine构建一个包装器并使用它来正确实现这些方法.希望这会有所帮助.