1. 概要

この記事では、マイクをキャプチャしてJavaで着信オーディオを録音し、WAVファイルに保存する方法を説明します。 マイクからの着信音をキャプチャするには、Javaエコシステムの一部であるJavaSoundAPIを使用します。

Java Sound APIは、オーディオをキャプチャ、処理、および再生するための強力なAPIであり、4つのパッケージで構成されています。 着信オーディオのキャプチャに必要なすべてのインターフェイスとクラスを提供するjavax.sound.sampledパッケージに焦点を当てます。

2. TargetDataLine とは何ですか?

TargetDataLineは、オーディオ関連データのキャプチャと読み取りを使用する一種のDataLineオブジェクトであり、マイクなどのオーディオキャプチャデバイスからデータをキャプチャします。インターフェイスは、データの読み取りとキャプチャに必要なすべてのメソッドを提供します。そして、ターゲットデータラインのバッファからデータを読み取ります。

AudioSystemのgetLine()メソッドを呼び出して、オーディオのすべてのトランスポート制御メソッドを提供するDataLine.Infoオブジェクトを提供できます。 Oracleのドキュメントでは、JavaSoundAPIがどのように機能するかについて詳しく説明しています。

Javaのマイクからオーディオをキャプチャするために必要な手順を見ていきましょう。

3. サウンドをキャプチャする手順

キャプチャされたオーディオを保存するために、JavaはAU、AIFF、AIFC、SND、およびWAVEファイル形式をサポートしています。 WAVE(.wav)ファイル形式を使用してファイルを保存します。

プロセスの最初のステップは、AudioFormatインスタンスを初期化することです。 AudioFormat は、着信サウンドストリーム内の情報のビットを解釈および処理する方法をJavaに通知します。 この例では、次のAudioFormatクラスコンストラクターを使用します。

AudioFormat(AudioFormat.Encoding encoding, float sampleRate, int sampleSizeInBits, int channels, int frameSize, float frameRate, boolean bigEndian)

その後、DataLine.Infoオブジェクトを開きます。 このオブジェクトは、データライン(入力)に関連するすべての情報を保持します。 DataLine.Infoオブジェクトを使用して、すべての着信データをオーディオストリームに読み込むTargetDataLineのインスタンスを作成できます。 TargetDataLine インスタンスを生成するには、[ X214X] AudioSystem.getLine()メソッドを実行し、DataLine.Infoオブジェクトを渡します。

line = (TargetDataLine) AudioSystem.getLine(info);

lineTargetDataLineインスタンスであり、infoDataLine.Infoインスタンスです。

作成したら、ラインを開いてすべての着信サウンドを読み取ることができます。 AudioInputStreamを使用して、着信データを読み取ることができます。 結論として、このデータをWAVファイルに書き込んで、すべてのストリームを閉じることができます。

このプロセスを理解するために、入力音を録音する小さなプログラムを見ていきます。

4. アプリケーション例

Java Sound APIの動作を確認するために、簡単なプログラムを作成してみましょう。 最初にAudioFormatを作成し、次に TargetDataLine を作成し、最後にデータをファイルとして保存するという3つのセクションに分けます。

4.1. AudioFormatの構築

AudioFormat クラスは、TargetDataLineインスタンスによってキャプチャできるデータの種類を定義します。 したがって、最初のステップは、新しいデータ行を開く前であっても、AudioFormatクラスインスタンスを初期化することです。 Appクラスはアプリケーションのメインクラスであり、すべての呼び出しを行います。 AudioFormat のプロパティは、ApplicationPropertiesという定数クラスで定義します。 必要なすべてのパラメーターをバイパスして、AudioFormatインスタンスを作成します。

public static AudioFormat buildAudioFormatInstance() {
    ApplicationProperties aConstants = new ApplicationProperties();
    AudioFormat.Encoding encoding = aConstants.ENCODING;
    float rate = aConstants.RATE;
    int channels = aConstants.CHANNELS;
    int sampleSize = aConstants.SAMPLE_SIZE;
    boolean bigEndian = aConstants.BIG_ENDIAN;

    return new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize / 8) * channels, rate, bigEndian);
}

AudioFormat の準備ができたので、先に進んでTargetDataLineインスタンスを構築できます。

4.2. TargetDataLineの構築

TargetDataLine クラスを使用して、マイクからオーディオデータを読み取ります。 この例では、SoundRecorderクラスのTargetDataLineを取得して実行します。 getTargetDataLineForRecord()メソッドは、TargetDataLineインスタンスを構築します。

オーディオ入力を読み取って処理し、AudioInputStreamオブジェクトにダンプしました。 TargetDataLineインスタンスを作成する方法は次のとおりです。

private TargetDataLine getTargetDataLineForRecord() {
    TargetDataLine line;
    DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
    if (!AudioSystem.isLineSupported(info)) {
        return null;
    }
    line = (TargetDataLine) AudioSystem.getLine(info);
    line.open(format, line.getBufferSize());
    return line;
}

4.3. AudioInputStreamの構築と入力

これまでの例では、 AudioFormat インスタンスを作成し、それを TargetDataLine、に適用し、データラインを開いてオーディオデータを読み取りました。 SoundRecorderインスタンスの自動実行に役立つスレッドも作成しました。 スレッドの実行時に最初にバイト出力ストリームを構築し、次にそれをAudioInputStreamインスタンスに変換します。 AudioInputStreamインスタンスを構築するために必要なパラメーターは次のとおりです。

int frameSizeInBytes = format.getFrameSize();
int bufferLengthInFrames = line.getBufferSize() / 8;
final int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;

上記のコードでは、bufferSizeが8減少していることに注意してください。 これは、バッファと配列を同じ長さにして、レコーダがデータを読み取るとすぐにラインに配信できるようにするためです。

必要なすべてのパラメーターを初期化したので、次のステップはバイト出力ストリームを構築することです。 次のステップは、生成された(キャプチャされたサウンドデータ)出力ストリームをAudioInputStreamインスタンスに変換することです。

buildByteOutputStream(out, line, frameSizeInBytes, bufferLengthInBytes);
this.audioInputStream = new AudioInputStream(line);

setAudioInputStream(convertToAudioIStream(out, frameSizeInBytes));
audioInputStream.reset();

InputStream を設定する前に、バイト OutputStream:を作成します

public void buildByteOutputStream(final ByteArrayOutputStream out, final TargetDataLine line, int frameSizeInBytes, final int bufferLengthInBytes) throws IOException {
    final byte[] data = new byte[bufferLengthInBytes];
    int numBytesRead;

    line.start();
    while (thread != null) {
        if ((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
            break;
        }
        out.write(data, 0, numBytesRead);
    }
}

次に、バイトOutstreamをAudioInputStream変換します。

public AudioInputStream convertToAudioIStream(final ByteArrayOutputStream out, int frameSizeInBytes) {
    byte audioBytes[] = out.toByteArray();
    ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
    AudioInputStream audioStream = new AudioInputStream(bais, format, audioBytes.length / frameSizeInBytes);
    long milliseconds = (long) ((audioInputStream.getFrameLength() * 1000) / format.getFrameRate());
    duration = milliseconds / 1000.0;
    return audioStream;
}

4.4. AudioInputStreamをWavファイルに保存する

AudioInputStream を作成して入力し、SoundRecorderクラスのメンバー変数として保存しました。 SoundRecorder インスタンスゲッタープロパティを使用して、AppクラスでこのAudioInputStreamを取得し、WaveDataUtilクラスに渡します。

wd.saveToFile("/SoundClip", AudioFileFormat.Type.WAVE, soundRecorder.getAudioInputStream());

WaveDataUtil クラスには、AudioInputStreamを.wavファイルに変換するコードがあります。

AudioSystem.write(audioInputStream, fileType, myFile);

5. 結論

この記事では、Java Sound APIを使用して、マイクを使用してオーディオをキャプチャおよび録音する簡単な例を示しました。 このチュートリアルのコード全体は、GitHubから入手できます。