< 目次

第5章: オーディオの取込み

取込みとは、コンピュータの外部から信号を取得する処理のことです。一般的なアプリケーションでのオーディオ取込みとは録音のことです。たとえば、マイクロフォン入力をサウンド・ファイルに録音する場合です。ただし、取込みと録音は同義語ではありません。録音という用語には、アプリケーションが受け取ったサウンド・データを常に保存するという意味があるためです。オーディオを取り込むアプリケーションの場合は、必ずしもオーディオを保存するとは限りません。データが入ってくるとそのデータになんらかの処理(発話をテキストに変換して複写するなど)を行いますが、バッファの処理が終わるとただちにバッファ内のオーディオを破棄する場合もあります。

第2章「Sampledパッケージの概要」で説明したように、Java Sound APIの実装の一般的なオーディオ入力システムは、次の要素で構成されています。

  1. 入力ポート(マイクロフォン・ポート、ライン入力ポートなど)。受け取ったオーディオ・データをミキサーに送ります。
  2. ミキサー。入力データをターゲット・データ・ラインに送ります。
  3. ターゲット・データ・ライン(少なくとも1つ)。アプリケーションがデータを取得する場所です。

    一般に、同時にオープンできる入力ポートは1つですが、オーディオ入力ミキサーで複数ポートからのオーディオをミキシングすることもできます。また、ポートを持たない代わりに、ネットワーク上でオーディオ入力を取得するミキサーによるシステム構成も考えられます。

    第2章「Sampledパッケージの概要」「Lineインタフェースの階層」で、TargetDataLineインタフェースについて簡単に説明しました。TargetDataLineは、第4章「オーディオの再生」で詳細に説明したSourceDataLineインタフェースにまさしく類似しています。すでに説明したように、SourceDataLineは、次の要素で構成されています。

同様に、TargetDataLineも次の要素で構成されます。

TargetDataLineのセット・アップ

ターゲット・データ・ラインを取得する手順については、第3章「オーディオ・システム・リソースへのアクセス」で説明しましたが、もう一度ここに示します。

TargetDataLine line;
DataLine.Info info = new DataLine.Info(TargetDataLine.class, 
format); // format is an AudioFormat object
if (!AudioSystem.isLineSupported(info)) { // Handle the error ... } // Obtain and open the line. try {
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format); } catch (LineUnavailableException ex) { // Handle the error ... }
AudioSystemではなくMixerの getLineメソッドを呼び出すこともできます。

この例で示すように、ターゲット・データ・ラインを取得したあとは、第4章「オーディオの再生」で説明したソース・データ・ラインの場合とまったく同様に、DataLineopenメソッドを呼び出してそのラインを予約します。単一パラメータのopenメソッドでは、そのラインのバッファはデフォルト・サイズになります。パラメータの2つのバージョンを呼び出して、アプリケーションの必要に応じたサイズにバッファを設定することもできます。

    void open(AudioFormat format, int bufferSize) 
バッファ・サイズが大きいと遅れが生じ、バッファ・サイズが小さいとデータを必要な速度で取得できない場合にオーディオに不連続部が発生するおそれがあります。このため、バッファ・サイズを決めるときは、両方の兼ね合いを考慮する必要があります。オーディオを取り込む場合、バッファがいっぱいになったら一定時間内にデータを取り出さなければ、データがオーバーフローする可能性があります。オーバーフローが起こると、取り込まれたデータの一部が破棄されるので、クリック・ノイズや音飛びの原因になります。これは、アンダーフローが原因で音が途切れる可能性のある再生の場合と逆の状況です。(バッファ・サイズの決定方法の詳細は、第4章「オーディオの再生」を参照。)

TargetDataLineからのデータの読込み

ラインがオープンされるとデータを取り込む準備が整いますが、そのラインはまだアクティブではありません。オーディオの取込みを実際に開始するには、DataLinestartメソッドを使用します。このメソッドは、アプリケーションが読み取れるように、そのラインのバッファに入力オーディオ・データを送り始めます。ラインからの読込みの準備が整っていないときにアプリケーションでstartを呼び出さないでください。取込みバッファへの書込みのために無駄な処理が発生し、オーバーフローが生じて、データは破棄されます。

バッファからのデータの取得を開始するには、TargetDataLineの readメソッドを呼び出します。

int read(byte[] b, int offset, int length) 
このメソッドは、配列bに、lengthで指定したバイト数のデータをoffsetで指定したオフセット位置から読み込もうとします。このメソッドは、実際に読み込まれたバイト数を返します。

SourceDataLineのwriteメソッドと同様に、このメソッドはバッファの何倍ものデータを要求された場合は要求された量のデータが配信されるまでブロックされるので、バッファに入りきらない量のデータを要求することができます。

録音時にアプリケーションがハング・アップするのを防ぐために、次の例のように、すべてのオーディオ入力を取得し終わるまでループ内で繰り返してreadメソッドを使用できます。

// Assume that the TargetDataLine, line, has already
// been obtained and opened.
ByteArrayOutputStream out  = new ByteArrayOutputStream();
int numBytesRead;
byte[] data = new byte[line.getBufferSize() / 5];

// Begin audio capture.
line.start();

// Here, stopped is a global boolean set by another thread.
while (!stopped) {
   // Read the next chunk of data from the TargetDataLine.
   numBytesRead =  line.read(data, 0, data.length);
   // Save this chunk of data.
   out.write(data, 0, numBytesRead);
}     
この例では、データを読み込むためのバイト配列のサイズはラインのバッファの1/5に設定されています。この配列をラインのバッファと同じ大きさにしてバッファ全体を読み込みたい場合は、タイミングを正確に計測しなければなりません。これは、データを読み込んでいる間にミキサーがラインにデータを送る必要が生じるとデータがダンプされるからです。この例のように、ラインのバッファ・サイズの数割程度を使うことにより、アプリケーションはラインのバッファへのアクセスをミキサーとうまく共有することができます。

TargetDataLinereadメソッドは、バイト配列、その配列内のオフセット、読み込む入力データのバイト数の3つの引数を取ります。この例では、3番目の引数は単にバイト配列の長さです。readメソッドは、実際に配列に読み込まれたバイト数を返します。

一般に、データはこの例のようにループ内でラインから読み込みます。whileループの中で、取得したデータの各チャンクがアプリケーションに適した方法で処理されます。この例では、ByteArrayOutputStreamに書き込まれます。ここには示されていませんが、独立したスレッドを使用してブール変数stoppedを設定し、ループを終了する方法もあります。このブール変数の値は、ユーザーが「停止」ボタンをクリックしたとき、およびリスナーがラインからCLOSEまたはSTOPイベントを受け取ったときにtrueに設定されます。CLOSEイベントにはリスナーが必須であり、STOPイベントにもリスナーを登録することをお薦めします。そうでないと、ラインがなんらかの原因で停止したときにstoppedがtrueに設定されず、whileループの反復のたびに取り込まれるバイト数が0バイトになり、実行速度が速くなってCPUサイクルが浪費されます。さらに、この例では、取込みが再びアクティブになったときにもう一度ループに入ります。

ソース・データ・ラインの場合と同様に、ターゲット・データ・ラインもドレインまたはフラッシュすることができます。たとえば、入力をファイルに録音する場合は、ユーザーが「停止」ボタンをクリックしたらdrainメソッドを呼び出します。drainメソッドを呼び出すと、ミキサーの残りのデータがターゲット・データ・ラインのバッファに送られます。データをドレインしない場合は、取り込まれたサウンドは最後で打ち切られたように見えます。

データのフラッシュが必要な場合もあります。データのフラッシュとドレインのどちらも行わないと、ミキサーにデータが残ります。ミキサーにデータが残っていると、取込みが再開されたときに、新しい録音の先頭にそのサウンドが入ってしまいます。これは、望ましくない場合があります。したがって、取込みを再開する前にターゲット・データ・ラインをフラッシュすることは有用です。

ラインのステータスのモニタリング

TargetDataLineインタフェースはDataLineを継承しているので、ターゲット・データ・ラインはソース・データ・ラインと同様にイベントを生成します。ターゲット・データ・ラインのオープン時、クローズ時、開始時、および停止時に必ずイベントを受け取るようにオブジェクトを登録できます。詳細は、第4章「オーディオの再生」「ラインのステータスのモニタリング」を参照してください。

入力オーディオの処理

ほかのいくつかのソース・データ・ラインと同様に、一部のミキサーのターゲット・データ・ラインは、ゲイン、パン、リバーブ、またはサンプリング・レートのコントロールのような信号処理コントロールを備えています。入力ポートには同様のコントロール、特にゲイン・コントロールがある場合があります。ラインがそのようなコントロールを備えているかどうかを調べる方法、およびそれらの使用方法の詳細は、第6章「コントロールを使ったオーディオ処理」を参照してください。

 


Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.