2016-08-09 43 views
13

tl; dr将来の読者のために、リアルタイムオーディオを録音するのはではありません(現在は)JavaまたはC#を使用しています。それはオーディオAPIの過多を提供するので、C + +を使用してください。Javaオーディオビジュアライザー - リアルタイムサウンド出力をスピーカーに取り込む方法は?


私の目標は、現在のサウンドは、Windowsマシン上で再生取得し、(ボリュームプロパティとヘルツ(ベースとトレブル)を取得)ないくらい、グラフィック、オーディオビジュアライザのような音を分析することです。私が現在のサウンドを言うとき、私はYoutubeビデオまたはSpotifyの曲を再生することを意味し、このプログラムはそのオーディオ出力を読むでしょう。私は音を演奏するつもりはないが、それをリアルタイムで取り込み、それを視覚化する。

私はbuild an audio waveform displayを読んで、オーディオファイルをバイト配列(a行)に変換する方法について説明しました。これは現在の音が得られないので助けになりません。私はまたcapture audioの方法についても読んでおり、this java accessing sound tutorialも、どちらも読み込みには曲ファイルが必要なので、私の質問には答えられません。

私はこれを全く理解していません。私は完全に無知だし、どんな助けも高く評価されるだろう。

編集:もう少し調べてみましたが、second answer from this sourceは次の結論に至りました。すべてのオーディオデバイスを見つけることができ、どちらがサウンドを生成しているのか確認できます。私はその後に何をすべきかわかりません。

編集2(編集済み):実験的に見て回って、以下のコードを書きました。私はこれが私が望む方向に私を得ると思うが、私はそれをどのように仕上げるのか分からない。

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

私はこのソースを使用:Checking The Level of Audio-Playback in a mixers lineを、私はボリュームを再生しているすべての行をチェックして見ていないよ、私は、ユーザーのデフォルトミキサーを必要とする、その行を取得し、データを分析することができます。

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

を私は上記のコードを使用して正しい道の上だと思うが、私は音を抽出し、BPM、ベースを見つける方法がわかりません、高音など

編集4:これは興味深い読書でした:Real-time low latency audio processing in Java。これは、実際にどのクラスをどのように実装するのかには触れませんが、いくつかの洞察を提供します。

編集5:@AndrewThompsonリンクに基づいてこのコードを使用して、使用可能なソースとターゲット行を繰り返し処理できました。

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

は、出力は次のようになります。

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 attemps:

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 

が、私はこのようになります。すべての行の音レベルを取得するメソッドを作成しました現在のライン演奏音を検出し、より高い音量を示す。これは返されます:

-1.0 
-1.0 
-1.0 
-1.0 
-1.0 
-1.0 

進歩しません。


新しいコード:

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

私は常に可能であるかどうかはわかりません。 *一部のコンピュータには、出力を記録するマイクのように機能する「ステレオミックス」入力があります。 – immibis

+0

あなたはいくつかのコンピュータを言うとき、あなたは精巧にできますか? (Windowsマシン、Macなどのように) – Eric

+0

私はいくつかのWindowsマシンでそれを見てきました。 – immibis

答えて

4

ラインからのPCMデータを抽出するためにあなたを助けるのJavaチュートリアルからの良い例があります。チュートリアルのUsing Files and Format Convertersには、「サウンドファイルの読み込み」という見出しの下にコード例があります。関連する部分は、「スニペット」一例であり、コードでマークされています

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

この時点で、あなたはラインの個々のバイトへのアクセスをHVE、そして取るとに従ってPCMにそれらを組み立てることができますサウンドファイルのフォーマット。バイトからPCMに行く具体的なことを扱ういくつかの他のスタックオーバーフローの質問があります。


コメントに応じてコードを追加しています。

TargetDataLineにキャストすることができないため、チュートリアルから抜粋して、私はTargetDataLineにラインをキャストすることができました。

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

しかし、私はちょうどCD品質のフォーマットスキームを使用して線をつかんだが、私が再生されているYouTubeチャンネルからの音を持っているラインを把握しようとしていません。


OPと私はチャットに行きましたが、これをハックし続けましたが、解決策を見つけることができませんでした。他の多くの人がこれを見て、あきらめているようです。私は恩恵が魅力的であることを証明することを望んでいます - これは興味深い問題です。

+0

この問題は、「どちらの場合でも、オーディオファイルに含まれるデータにアクセスする必要があります」です。私はラインで送出されたリアルタイムのオーディオを抽出するために探しています。 Javaチュートリアルのメソッドは、既存のサウンドファイルを処理します。 – Eric

+0

.getLevel()メソッドが不審です。アクティブなラインのレベルで何かをしようとする試みが完全に失敗した例がありましたので、私はいつも私の投稿に記述されているバイト/ DSPレベルで作業します。私は主にシンセサイザーを使って生の世代を扱っているので、私は既存のファイルではなくリアルタイムのラインで作業しています。私は入ってくるライブサウンドではあまりやっていない。しかし、チュートリアルではラインの特定方法(およびTargetDataLineの使用方法)について説明しています。私が言及したルーチンは、実際にデータが流れていて、0の文字列だけでなくリアルタイムでテストするために使用できます。 –

+0

チュートリアルを読んだ後、TargetDataLine()は録音ポートからの着信オーディオのキャプチャを可能にします。私が把握できないのは、ラインインポートを割り当てて、ポートが制御できるTargetDataLineを作成する方法です。 – Eric

関連する問題