2016-08-09 101 views
13

tl; dr Gelecek okuyucular için, gerçek zamanlı ses kaydı mümkün değil (şimdilik) Java veya C# ile. Ses api'sinin bolluğunu sağladığı için C++ kullanın.Java ses görselleştiricisi - Hoparlörde gerçek zamanlı ses çıkışı nasıl alınır?


Amacım akım ses Windows makinesinde oynanan almak ve (hacim özelliği ve Hz (baz ve tiz) olsun) yok çok bir grafik ses görselleştiricisi gibi ses analiz etmektir. Mevcut ses dediğimde, bir Youtube videosu veya Spotify şarkısı çalınırsa, bu program bu ses çıkışını okuyacaktır. Ses çalmak gibi bir niyetim yok ama onu gerçek zamanlı olarak yakala ve görselleştir.

Bunu yapmayı denerken, build an audio waveform display'un nasıl yapıldığını okudum ve bir ses dosyasını bir bayt dizisine (bir Satır) nasıl dönüştüreceğime dokunur. Bu işe yaramaz çünkü mevcut sesi alamıyor. Ayrıca, capture audio'un ve this java accessing sound tutorial'un nasıl okunduğunu da okudum, bunların ikisi de yüklenecek bir şarkı dosyası gerektirdiklerinden sorumu yanıtlamadı.

Sadece bunu anlamıyorum. Tamamen clueless ve herhangi bir yardım takdir edilecektir.

Düzenleme: Biraz daha etrafa baktım ve second answer from this source beni şu sonuca götürdü: Tüm ses aygıtlarını bulabilirim, hangisinin ses çıkardığını görebiliyorum. Bundan sonra ne yapacağımı bilmiyorum.

Düzenleme 2 (yeniden düzenlenmiş): Deneme ve etrafa bakmadan, aşağıdaki kodu yazdım. Sanırım bu beni istediğim yönde alıyor, ama nasıl bitireceğimi bilmiyorum. Ben sadece kullanıcılar varsayılan Karıştırıcı, o Hattı almak gerekir ve verileri analiz edebilmek Checking The Level of Audio-Playback in a mixers line ama hacmini oynayan tüm hatları kontrol etmek aramıyorum:

Mixer.Info[] mixers = AudioSystem.getMixerInfo(); 
    for (Mixer.Info mixerInfo : mixers) { 
     Mixer mixer = AudioSystem.getMixer(mixerInfo); 
     try { 
      mixer.open(); 
      Line.Info[] lines = mixer.getTargetLineInfo(); 
      for (Line.Info linfo : lines) { 

       Line line = AudioSystem.getLine(linfo); 

       //here I'm opening the line, but I don't know how to grab data 
       line.open(); 

      } 
     } catch (LineUnavailableException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

Bu kaynağı kullandım .

Düzenleme 3:

//creating a format for getting sound 
    float sampleRate = 8000; 
    int sampleSizeInBits = 16; 
    int channels = 2; 
    boolean signed = true; 
    boolean bigEndian = true; 
    AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits, channels, 
     signed, bigEndian); 

    //creating a line based off of the format 
    DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); 
    TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info); 

    //opening and starting that line 
    line.open(format); 
    line.start(); 

    while (conditionIsTrue){ 
     //here, I don't know what to put as the parameters. 
     //Had I known, I don't know how I would get to analyze the data 
     line.read(); 
    } 

ben yukarıdaki kodu kullanarak doğru yolda olduğumu düşünüyorum, ama sesi çıkarmak için nasıl bilir ve bpm, taban bulmuyorum: ben denedim tiz, vb.

Düzenleme 4: Bu ilginç bir okuma oldu: Real-time low latency audio processing in Java. Bu, hangi sınıflara ve bunu gerçekte nasıl uygulayacağımıza değinmez, ancak bazı içgörüler sağlar.

Düzenleme 5: @AndrewThompson Bağlantınıza bağlı olarak bu kod parçasını kullanarak, kullanılabilir kaynak ve hedef satırlarını yineleyebildim.

Mixer.Info[] mixers = AudioSystem.getMixerInfo(); 
    for (Mixer.Info mixerInfo : mixers) { 
     Mixer mixer = AudioSystem.getMixer(mixerInfo); 
     try { 
      mixer.open(); 
      Line.Info[] sourceLines = mixer.getSourceLineInfo(); 
      Line.Info[] targetLine = mixer.getTargetLineInfo(); 
      for (Line.Info sourceLinfo : sourceLines) { 
       System.out.println(sourceLinfo); 
      } 
      for (Line.Info targetLinefo : targetLine) { 
       System.out.println(targetLinefo); 
      } 

     } catch (LineUnavailableException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

çıktı şuna benzer:

private static void getVolumeOfAllLines() { 
    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) { 
       DataLine line = (DataLine)AudioSystem.getLine(linfo); 
       if(line != null) 
        System.out.println(line.getLevel()); 
      } 
     } catch (LineUnavailableException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

-in çalışılmıştır:

interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes 
interface Clip supporting 8 audio formats, and buffers of at least 32 bytes 
interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes 
interface Clip supporting 8 audio formats, and buffers of at least 32 bytes 
interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes 
interface Clip supporting 8 audio formats, and buffers of at least 32 bytes 
HEADPHONE target port 
SPEAKER target port 

Sonra şöyle bütün çizgilerin ses seviyelerini alır bir yöntem oluşturduk Mevcut ses çalma sesini bulmak için daha yüksek bir ses düzeyini gösterir. Bu, şu şekilde döner:

Devam yok.


Yeni Kod:

bir hattan PCM veri ayıklamak için yardımcı olacaktır Java öğreticiler iyi bir örnek vardır
private static void debug(){ 
    Mixer.Info[] mixers = AudioSystem.getMixerInfo(); 
    for (Mixer.Info mixerInfo : mixers) { 
     Mixer mixer = AudioSystem.getMixer(mixerInfo); 
     try { 
      mixer.open(); 
      Line.Info[] lines = mixer.getTargetLineInfo(); 


      AudioFormat format = new AudioFormat(
        AudioFormat.Encoding.PCM_SIGNED, 
        44100, 
        16, 2, 4, 
        44100, false); 

      AudioFormat[] tdl = AudioSystem.getTargetFormats(AudioFormat.Encoding.PCM_SIGNED, format); 

      for (Line.Info linfo : lines) { 

       //Line line = AudioSystem.getLine(linfo); 


       TargetDataLine line = null; 
       DataLine.Info info = new DataLine.Info(TargetDataLine.class, 
         format); // format is an AudioFormat object 
       if (!AudioSystem.isLineSupported(info)) 
       { 
        System.out.println("line not supported:" + line); 
       } 

       try 
       { 
        line = (TargetDataLine) AudioSystem.getLine(info); //error 
        line.open(format); 
        System.out.println("line opened:" + line); 

        line.start(); 

        byte[] buffer = new byte[1024]; 
        int ii = 0; 
        int numBytesRead = 0; 
        while (ii++ < 100) { 
         // Read the next chunk of data from the TargetDataLine. 
         numBytesRead = line.read(buffer, 0, buffer.length); 

         System.out.println("\nnumBytesRead:" + numBytesRead); 
         if (numBytesRead == 0) continue; 
         // following is a quickie test to see if content is only 0 vals 
         // present in the data that was read. 

         for (int i = 0; i < 16; i++) 
         { 
          if (buffer[i] != 0) 
           System.out.print("."); 
          else 
           System.out.print("0"); 
         } 
        } 

       } catch (LineUnavailableException ex) { 
        ex.printStackTrace(); 
        //... 
       } 
      } 
     } catch (LineUnavailableException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

Her zaman mümkün olduğundan emin değilim. * Bazı * bilgisayarlarda, çıkışı kaydeden bir mikrofon gibi davranan bir "Stereo Mix" girişi bulunur. – immibis

+0

Bazı bilgisayarları söylediğinde, detaylandırır mısın? (Sadece windows makinelerinde olduğu gibi, mac, vb) – Eric

+0

Bazı Windows makinelerinde gördüm. – immibis

cevap

4

. Using Files and Format Converters başlıklı eğiticide "Ses Dosyalarını Okuma" başlığı altındaki bir kod örneği bulunmaktadır. İlgili kısım "pasajı" örneğidir ve kod tarafından işaretlenir:

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

Bu noktada, haddini bireysel bayt erişimi hve ve alıp göre PCM içine monte edebilirsiniz ses dosyasının formatı. Bayt'a ve PCM'ye gitmenin özellikleriyle ilgilenen birçok stackoverflow sorusu vardır.


Açıklamalara yanıt olarak bir kod ekliyorum.

TargetDataLine'a yayınlanamayan her biri, eğitimciden ayıklanan, TargetDataLine'a bir satır göndermeme izin verdi.

AudioFormat format = new AudioFormat(
     AudioFormat.Encoding.PCM_SIGNED, 
     44100, 
     16, 2, 4, 
     44100, false); 

    TargetDataLine line = null; 
    DataLine.Info info = new DataLine.Info(TargetDataLine.class, 
     format); // format is an AudioFormat object 
    if (!AudioSystem.isLineSupported(info)) 
    { 
     System.out.println("line not supported:" + line); 
    } 

    try 
    { 
     line = (TargetDataLine) AudioSystem.getLine(info); 
     line.open(format); 
     System.out.println("line opened:" + line); 

     line.start(); 

     byte[] buffer = new byte[1024]; 
     int ii = 0; 
     int numBytesRead = 0; 
     while (ii++ < 100) { 
     // Read the next chunk of data from the TargetDataLine. 
      numBytesRead = line.read(buffer, 0, buffer.length); 

      System.out.println("\nnumBytesRead:" + numBytesRead); 
       if (numBytesRead == 0) continue; 
    // following is a quickie test to see if content is only 0 vals 
    // present in the data that was read. 

       for (int i = 0; i < 16; i++) 
       { 
        if (buffer[i] != 0) 
         System.out.print("."); 
        else 
         System.out.print("0"); 
       } 
      } 

     } catch (LineUnavailableException ex) { 
      ex.printStackTrace(); 
     //... 
    } 
} 

Ama sadece CD kalitesinde biçimi şemasını kullanarak bir çizgi kapma ediyorum, oynuyor YouTube kanalından sesi var hangi satır anlamaya denemedim.


OP ve sohbet etmeye gittim ve bu konuda hack yapmaya devam ettim, ancak bir çözüm için çalışamadık. Diğerleri de buna bakıp vazgeçmiş gibi görünüyor. Ben ödülün cazibesini kanıtladığını umuyorum - bu ilginç bir konu.

+0

Bununla ilgili sorun "Her iki durumda da, ses dosyasında bulunan verilere erişmeniz gerekiyor". Bir hat tarafından gönderilen gerçek zamanlı ses çıkarmak istiyorum. Java öğreticileri üzerindeki yöntemler önceden varolan ses dosyalarıyla ilgilenir. – Eric

+0

.getLevel() yönteminden şüpheleniyorum.Etkin bir çizginin düzeyi ile bir şey yapmaya çalışmanın tamamen başarısız olduğu durumlar olmuştur, bu yüzden her zaman postada belirtildiği gibi bayt/DSP düzeyinde çalışıyorum. Ben çoğunlukla sentez yoluyla canlı üretimi ele alıyorum, bu yüzden varolan dosyalar olmayan gerçek zamanlı hatlarla çalışıyorum. Gelen canlı sesle fazla bir şey yapmadım. Ancak öğreticiler, satırların nasıl tanımlanacağını (ve TargetDataLine'in nasıl kullanılacağını) açıklar ve bahsettiğim rutin, gerçekte sadece 0'lık bir dizi değil, gerçek zamanlı olarak veri akışı olup olmadığını test etmek için kullanılabilir. –

+0

Öğreticiler okunduktan sonra, TargetDataLine(), gelen seslerin kayıt portlarından yakalanmasını sağlar. Anlayamadığım şey, bir giriş bağlantı noktası atamak ve bir Port'un denetleyebileceği bir TargetDataLine oluşturmaktır. – Eric