1

コンピューターのマイクからオーディオを読み取り、何らかの方法で変更して (今はテストするだけです)、スピーカーから再生するプログラムを作成しようとしています。そのままでは問題なく動作しますが、音声がマイクから入力されてから聞こえるまでの間に非常に顕著な遅延があるため、これを減らす方法を見つけようとしています. 遅延を完全に取り除くことはほとんど不可能であることは承知していますが、少なくともほとんど聞こえないようにする方法を探しています.

コードは次のとおりです。

package com.funguscow;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;

public class Listen {

    public static void main(String[] args){
        AudioFormat format = new AudioFormat(44100, 16, 2, true, true); //get the format for audio

        DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, format); //input line
        DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format); //output line

        try {
            TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo);
            targetLine.open(format);
            targetLine.start();

            SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(sourceInfo);
            sourceLine.open(format);
            sourceLine.start();

            int numBytesRead;
            byte[] targetData = new byte[sourceLine.getBufferSize()];

            while (true) {
                numBytesRead = targetLine.read(targetData, 0, targetData.length); //read into the buffer

                if (numBytesRead == -1) break;

                for(int i=0; i<numBytesRead/2; i++){ //apply hard distortion/clipping
                    int j = (((targetData[i * 2]) << 8) & 0xff00) | ((targetData[i * 2 + 1]) & 0xff);
                    j *= 2;
                    if(j > 65535) j = 65535;
                    if(j < 0) j = -0;
                    targetData[i * 2] = (byte)((j & 0xff00) >> 8);
                    targetData[i * 2 + 1] = (byte)(j & 0x00ff);
                }

                sourceLine.write(targetData, 0, numBytesRead); //play
            }
        }
        catch (Exception e) {
            System.err.println(e);
        }
    }

}

このままだと1秒くらい遅れそうなのですが、これを改善することはできますか?

4

2 に答える 2

1

Buffer サイズで最終的な int を宣言します。10 ミリ秒の遅延は、フレームあたりのバイト数に 1 秒あたりのフレーム数を掛けて 100 で割った値になります。ステレオ 16 ビット エンコーディング (CD 品質) が 44100fps である場合、(4 * 44100)/100 = 1764 バイトになります。 .

次に、そのバッファー サイズで TargetDataLine と SourceDataLine の両方を開きます。

targetLine.open(format, BUFFER_SIZE);
sourceLine.open(format, BUFFER_SIZE);

行が指定したサイズを実際に使用していることを確認し、バッファ配列の新しいバイト宣言でも検証済みの値を使用します。

読み取りと書き込みでも定数を使用します。

値を最適化するには、値をいじる必要があるかもしれません。したがって、一度だけ定義するのが理にかなっているので、複数の編集を行う必要はありません。この値は、整数のフレーム数が読み取りまたは書き込みに含まれるのに必要なバイト数に対応している必要があります。高すぎるとレイテンシが増加し、低すぎるとドロップアウトの可能性が高くなります。

過度にパーカッシブなサウンドを扱っていない場合は特に、10 ミリはかなり良いパフォーマンスです。

編集、9/20: 今日誰かが賛成票を投じたとき、私はこの投稿を思い出しました。バッファーの問題は、OP の 1 秒のレイテンシーを引き起こした主な原因であった可能性がありますが、バッファーを小さくすることは 1 つの手段にすぎません。最近学んだもう 1 つの方法は、入力と編集/出力の間にバッファーを使用することです。その理由は、マイキングと再生の両方の処理が急増するためです。それらが直接結びついている場合、より遅いプロセスがペースを定義します。間に緩衝材があれば、どちらも他方を妨げずに多少曲げることができます。

于 2015-12-16T23:44:34.593 に答える
0

から返されるバッファの大きさはsourceLine.getBufferSize()? 2 バイト/サンプルで 44,100 サンプル/秒でマイクから読み取っている場合、88,200 バイトのバッファーを満たすのにちょうど 1 秒かかります。システムによって決定されるバッファは、そのサイズに近いと思います。byte[] targetData = new byte[sourceLine.getBufferSize()];最適なユーザー エクスペリエンスを得るには、オーディオ レイテンシが 10 ミリ秒以下 (つまり 882 バイト以下) になるように十分に小さいバッファーを使用することをお勧めします。

于 2015-12-16T23:13:19.253 に答える