2014-03-01 7 views
6

Ich versuche herauszufinden, ob Sound jeder Art in Windows (von irgendeiner Anwendung) spielt. Wenn irgendwo etwas laut wird, will ich davon wissen!Überprüfen des Pegels der Audiowiedergabe in der Line eines Mixers?

Nachdem ich die Dokumente gelesen habe, habe ich herausgefunden, wie man eine Liste von Mischern auf der Maschine bekommt, sowie Linien für diese Mischer - die, wenn ich richtig verstehe, für die Eingabe/Ausgabe der Rührgerät.

Allerdings ist das Problem, das ich habe, dass ich nicht weiß, wie man die Daten erhält, die ich von der Linie benötige.

Die einzige Schnittstelle, die ich sehe, die eine Vorstellung von der Lautstärke hat, ist DataLine. Das Problem damit ist, dass ich nicht herausfinden kann, was ein Objekt zurückgibt, das die Datenschnittstelle implementiert.

alle der Mischer und Linien Aufzählen:

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(); 
     } 
    } 

Dieser Code aufzählt und zeigt alle der Audiogeräte auf meinem Rechner. Darf also nicht eine dieser Lines eine Art von Playback-Level-Daten enthalten?

+0

Sie können ein Audio- oder Javasound-Tag hinzufügen, um Benutzer mit diesem speziellen Interesse zu warnen! –

Antwort

6

Oh, Sie möchten die Lautstärke finden? Nun, nicht alle Hardware unterstützt es, aber hier ist, wie Sie die Dataline bekommen.

Rufen Sie dann einfach SourceDataLine.getLevel() auf, um das Volume abzurufen. Ich hoffe das hilft.

Hinweis: Wenn der Sound von außerhalb der JVM stammt oder nicht über die JavaSound-API, erkennt diese Methode den Sound nicht, da die JVM keinen Zugriff auf das OS-Äquivalent der SourceDataLine hat.

UPDATE: Nach weiteren Untersuchungen ist getLevel() auf den meisten Systemen nicht implementiert. So habe ich manuell implementiert das Verfahren in diesem Forum Diskussion basiert off: https://community.oracle.com/message/5391003

Hier sind die Klassen:

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)); 
    } 
} 

Die Methode, die ich nur auf 8bitPCM arbeitet verwendet, so haben wir die Codierung konvertieren, dass diese beiden mit Klassen. Hier ist die allgemeine abstrakte Konverterklasse.

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(); 
    } 
} 

Und hier ist das eine für 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]; 
    } 




} 

Diese für TargetDataLine ist, die in ihrem Anwendungsfall kann nicht funktionieren, aber Sie könnten einen Wrapper um SourceDataLine zu bauen und diese richtig diese Methoden zu implementieren verwenden . Hofft, das hilft.

Verwandte Themen