注
|
ここでは、Java Sound API のデジタルオーディオアーキテクチャーの概要を説明します。アーキテクチャーには javax.sound.sampled
パッケージからアクセスできます。最初に、パッケージの中心機能である整形済みのオーディオデータの再生と取り込みについて説明します。次に、再生と取り込みに必要な 3 つの基本コンポーネントである、オーディオデータ形式、ライン、ミキサーについて説明します。Line
インタフェースとそのサブインタフェースについては簡潔に説明します。
Java Sound API の要素の考察を始める前に、javax.sound.sampled
パッケージの位置付けについて説明します。
javax.sound.sampled
パッケージは、音声の移送に関係するものです。つまり、Java Sound API は、再生と取り込みが中心であると言えます。Java Sound API が取り組む主なタスクは、整形済みオーディオデータのバイトをシステムの内外にどのように移動させるかということです。このタスクには、オーディオ入出力デバイスのオープン、およびリアルタイムのサウンドデータを格納する複数のバッファーの管理が伴います。また、入力であれ出力であれ、複数のオーディオストリームを 1 本のストリームにミキシングする作業も伴います。ユーザーがサウンドのフローの開始、一時停止、再開、停止を要求するとき、システム内外へのサウンドの転送は、適切に処理される必要があります。
基本のオーディオ入出力を中心的にサポートするため、Java Sound API にはさまざまなオーディオデータ形式間での変換用のメソッドと、一般的な種類のサウンドファイルの読み込み/書き込み用のメソッドが提供されています。ただし、この API は包括的なサウンドファイルツールキットを目指すものではありません。特定の Java Sound API の実装では、ファイルタイプやデータ形式変換の拡張セットのサポートを必要としません。サードパーティーのサービスプロバイダから、既存の実装にプラグインして追加のファイルタイプとファイル変換をサポートできるモジュールが提供されています。
Java Sound API では、バッファー付き方式のストリーミングと、バッファーなしのメモリー内方式のストリーミングの両方で音声の転送を処理することができます。ここでは「ストリーミング」という用語はオーディオバイトのリアルタイム処理という一般的な意味で使用し、インターネット上でよく使用されるオーディオ送信という特定の形式で使用される場合を指しません。つまり、オーディオのストリームとは単に、処理 (再生、録音など) されるレートとほぼ同じレートで到着する連続したオーディオバイト群です。バイトに対する操作は、すべてのデータが到着する前に開始します。ストリーミングモデルで、特にオーディオ出力ではなくオーディオ入力の場合は、サウンドの長さと、すべてが到着するまでの時間があらかじめわかっているとは限りません。操作が停止するまで、バッファー内のオーディオデータを一度に 1 つずつ処理するだけです。オーディオ出力 (再生) の場合も、再生するサウンドが大きすぎて一度にメモリーに入りきらないときは、データをバッファリングする必要があります。つまり、オーディオバイトを複数のチャンク (塊) に分けてサウンドエンジンに渡し、サウンドエンジンは適切な時に各サンプルの再生処理を行います。各チャンクの適正なデータ量を簡単に知るためのメカニズムが用意されています。
Java Sound API では、再生のみの場合はバッファーなしの転送も可能ですが、すべてのオーディオデータが手元にあり、メモリーに入りきるサイズであることが条件です。この場合は、アプリケーションプログラムによるオーディオのバッファリングは必要ありませんが、必要に応じてバッファー付きのリアルタイム技法を利用することもできます。また、あらかじめサウンド全体をいったんメモリーにロードしておいてから再生することもできます。この方法ではあらかじめすべてのサウンドデータがロードされているので、たとえばユーザーが「開始 (Start)」ボタンをクリックすると同時に再生を開始できます。この方法は、最初のバッファーがいっぱいになるまで待つ必要のあるバッファー付きモデルよりも有利です。さらに、バッファーなしのメモリー内方式のモデルでは、簡単にサウンドをループ (循環) させたりデータ上の任意の位置にセットしたりすることができます。
この再生のための 2 つのモデルについては第 4 章「オーディオの再生」で詳細に説明します。バッファー付きの録音については、第 5 章「オーディオの取り込み」で説明します。
Java Sound API を使ってサウンドを再生したり取り込んだりするには、少なくとも、整形済みオーディオデータ、ミキサー、およびラインの 3 つの要素が必要です。次に、それぞれについて説明します。
整形済みオーディオデータとは、いくつかの標準形式のうちのいずれかにフォーマットされているサウンドを指します。Java Sound API では、「データ形式」と「ファイル形式」を区別しています。
データ形式は、「raw」サンプリングオーディオデータ (すでにサウンドファイルから読み取られているサンプルやマイクロフォン入力から取り込まれているサンプルなど) の一連のバイトを解釈する方法を示します。たとえば、1 つのサンプルが何ビットで構成されているか (サウンドの最短瞬間の表示) や、サウンドのサンプリングレート (サンプリングの間隔) を知る必要があります。再生または取り込みの設定を行うときは、再生または取り込みを行うサウンドのデータ形式を指定します。
Java Sound API ではデータ形式は AudioFormat
オブジェクトで表されます。このオブジェクトには次の属性があります。
1 つのフレームには、特定の時間のすべてのチャネルのデータが含まれます。PCM エンコーディングデータの場合は、フレームは単に所定の瞬間におけるすべてのチャネルの同時サンプルのセットであり、それ以外の情報は付随しません。この場合、フレームレートはサンプリングレートに等しく、バイト単位のフレームサイズは、チャネル数×ビット単位のサンプルサイズ÷バイト内のビット数で求められます。
その他のエンコーディング手法では、フレームにサンプル以外の情報が付随することがあります。またフレームレートがサンプリングレートとまったく異なることがあります。たとえば、MP3 (MPEG-1 Audio Layer 3) エンコーディングを考えます。この手法は Java Sound API の現バージョンでは明示的には言及してはいませんが、Java Sound API の実装またはサードパーティーサービスプロバイダによりサポートされる場合があります。MP3 では、各フレームにはチャネルごとのサンプルだけでなく、一連のサンプルのまとまった圧縮データが含まれます。各フレームにサンプル群全体が縮約されるため、フレームレートはサンプリングレートよりも遅くなります。フレームにはヘッダーも含まれます。ヘッダーがあっても、バイト単位のフレームサイズは、相当する数の PCM フレームを合計したバイトサイズよりも小さくなります。つまり、MP3 は、PCM よりもコンパクトなデータにすることを目的としています。このようなエンコーディングでは、サンプリングレートとサンプルサイズとは、エンコードされた音声の最終的な変換目的であり、DA コンバータ (DAC) に渡される、PCM データのことです。
ファイル形式は、サウンドファイルの構造について、ファイル内の raw オーディオデータの形式だけでなくファイル内に保存できるほかの情報も含めて指定します。サウンドファイルには、WAVE (WAV としても知られ、PC に関連する場合が多い)、AIFF (Macintosh に関連する場合が多い)、AU (UNIX システムに関連する場合が多い) などのさまざまな標準形式があります。サウンドファイルのタイプが異なるとそれぞれの構造も異なります。たとえば、ファイルのヘッダー内のデータの配列が異なることがあります。ヘッダーには説明情報が含まれ、通常はファイルの実際のオーディオサンプルの前にありますが、ファイル形式によっては説明とオーディオデータを連続した「チャンク」の形にすることもあります。ヘッダーには、そのオーディオをサウンドファイルに保存するために使用したデータ形式の指定が含まれます。どのタイプのサウンドファイルでもさまざまなデータ形式を使用できます (通常は 1 つのファイルに 1 つのデータ形式)。また、異なるファイル形式のファイルに同じデータ形式を使用することもできます。
Java Sound API ではファイル形式は AudioFileFormat
オブジェクトで表されます。このオブジェクトには次の属性があります。
AudioSystem
クラス (第 3 章「オーディオシステムリソースへのアクセス」を参照) には、異なるファイル形式でサウンドの読み込みと書き込みを行うためのメソッドと、異なるデータ形式間における形式の変換のためのメソッドがあります。これらのメソッドの中には、AudioInputStream
と呼ばれる一種のストリームを介してファイルの内容にアクセスできるものがあります。AudioInputStream
はジェネリック Java InputStream
クラスのサブクラスで、順次に読み出されるバイト群をカプセル化しています。AudioInputStream
はスーパークラスの InputStream に、そのバイトのオーディオデータ形式の知識 (AudioFormat
オブジェクトで表される) を追加したものです。サウンドファイルを AudioInputStream
として読み込むことにより、サウンドファイルの構造 (ヘッダー、チャンクなど) を考慮する必要なくサンプルに直接アクセスできます。1 回のメソッド呼び出しで、データ形式とファイルタイプについて必要なすべての情報を取得できます。
サウンド用のアプリケーションプログラミングインタフェース (API) の多くは、オーディオデバイスという概念を使用します。デバイスとは、多くの場合、物理的な入出力装置へのソフトウェアインタフェースのことです。たとえば、サウンド入力デバイスは、マイクロフォン入力、ラインレベルのアナログ入力、場合によってはデジタルオーディオ入力など、サウンドカードの入力機能を表すことがあります。
Java Sound API では、デバイスは、Mixer
オブジェクトによって表されます。ミキサーの目的は、1 つまたは複数のオーディオ入力ストリームと、1 つまたは複数のオーディオ出力ストリームを処理することです。通常の場合、ミキサーは実際、複数の入力ストリームをミキシングして 1 本の出力ストリームにします。Mixer
オブジェクトは、サウンドカードのような物理装置のサウンドミキシング機能を表すことができます。そのような装置では、さまざまな入力装置からコンピュータに送られるサウンドやアプリケーションプログラムから出力装置へ送られるサウンドをミキシングする必要があります。
また一方で、Mixer
オブジェクトは、物理装置への固有のインタフェースを持たずに完全にソフトウェア内に実装したサウンドミキシング機能を表すこともできます。
Java Sound API では、サウンドカード上のマイクロフォン入力などの構成コンポーネントは、それ自体ではデバイス (ミキサー) とは見なされず、ミキサーへの入出力のポートと見なされます。ポートは通常、ミキサーに入る、またはミキサーから出ていく 1 本のオーディオストリームを作ります。ただし、ストリームはステレオのように複数チャネルでも構いません。ミキサーには、このようなポートが複数あることがあります。たとえば、サウンドカードの出力機能を表すミキサーは複数のオーディオストリームをミキシングして、ミキサーに接続しているさまざまな出力ポートの 1 つまたはすべてにミキシングした信号を送ります。これらの出力ポートとして、ヘッドフォンジャック、内蔵スピーカー、ラインレベル出力などがあります。
ライブコンサートやレコーディングスタジオで使われている実際のミキシングコンソールを思い浮かべると、Java Sound API のミキサーの概念が理解しやすくなります。(下の図を参照。)
物理ミキシングコンソール物理装置としてのミキサーには複数の「ストリップ」(スライスとも呼ばれる) があり、それぞれのストリップは 1 つのオーディオ信号が処理のためにミキサーに送られる経路を表します。ストリップには、そのストリップ内の信号のボリュームとパン (ステレオイメージでの配置) を調節するためのつまみとコントロールがあります。また、ミキサーにはリバーブ (残響) などのサウンドエフェクトのための独立したバスがあり、内部または外部のリバーブユニットにこのバスを接続できます。各ストリップには、そのストリップの信号のうち、リバーブをかける信号の量を調節するポテンショメータがあります。リバーブをかけた (「ウェット」) ミックスは、次にストリップからの「ドライ」の信号とミキシングされます。物理ミキサーは、ミキシングされたこの最終信号を出力バスに送り、出力バスは通常はテープレコーダー (またはディスクによる録音システム) とスピーカーに接続しています。
ライブコンサートのステレオ録音をイメージしてみてください。ステージ上の多数のマイクや電子楽器から出ているケーブル (または無線接続) はミキシングコンソールの入力プラグに差し込まれています。それぞれの入力は、図に示すようにミキサーの別々のストリップにつながっています。音響技師が、ゲイン、パン、リバーブ調節の設定を決めます。すべてのストリップとリバーブユニットの出力が 2 本のチャネルにミキシングされます。この 2 本のチャネルは、ミキサーの 2 つの出力に送られます。この出力には、ステレオテープレコーダーの入力に接続しているケーブルが差し込まれています。この 2 本のチャネルは、音楽の種類とホールの大きさに応じて、ホール内のスピーカーにアンプを介して送られます。
次に、録音スタジオで、楽器や歌手の音声をマルチトラックテープレコーダーの別々のトラックに録音する場合を考えます。すべての楽器と歌手の音声を録音し終わってから、録音技師が「ミックスダウン」を行い、テープ録音されたすべてのトラックをまとめて、コンパクトディスクで配布可能な 2 チャネル (ステレオ) 録音にします。この場合、ミキサーの各ストリップへの入力はマイクロフォンではなく、マルチトラック録音の 1 つのトラックです。ここでも、録音技師はストリップのコントロールを使って、各トラックのボリューム、パン、およびリバーブの量を決定することができます。ライブコンサートの例と同様に、ミキサーの出力は今度もステレオレコーダーとステレオスピーカーに送られます。
上記の 2 つの例は、ミキサーの 2 つの使用方法を示しています。複数の入力チャネルを取り込んで少数のトラックにまとめて記録し、ミキシング済みの信号を保存する方法と、複数のトラックを再生しながら少数のトラックにミックスダウンする方法です。
Java Sound API では、ミキサーは入力 (オーディオの取り込み) と出力 (オーディオの再生) に同様に使用できます。入力の場合は、ミキシングのためのオーディオを取得するソースは、1 つ以上の入力ポートです。ミキサーは、取り込んでミキシングしたオーディオストリームをターゲットに送ります。ターゲットは、アプリケーションプログラムがミキシング済みオーディオデータを取り出すことのできる、バッファーを持つオブジェクトです。オーディオ出力の場合は、状況が逆になります。ミキサーのオーディオソースは、1 つ以上のアプリケーションプログラムがサウンドデータを書き込むことのできる複数のバッファーを持つ 1 つ以上のオブジェクトであり、ミキサーのターゲットは 1 つ以上の出力ポートです。
物理ミキシングコンソールの例は Java Sound API のラインの概念の理解にも役立ちます。
ラインとは、デジタルオーディオ「パイプライン」、つまりオーディオをシステムの内外に移送するための経路の 1 つの要素です。通常、ラインはミキサーへの入力または出力の経路です (技術的には、ミキサー自体も一種のラインです)。
オーディオ入出力ポートはラインです。これらは、物理ミキシングコンソールに接続されているマイクロフォンとスピーカーに似ています。ラインの種類にはこのほか、アプリケーションプログラムがミキサーから入力オーディオを取得したりミキサーに出力オーディオを送るために使用するデータパスがあります。これらのデータパスは、物理ミキシングコンソールに接続されているマルチトラックレコーダーのトラックに似ています。
Java Sound API のラインと物理的なミキサーのラインの違いの 1 つは、Java Sound API のラインを流れるオーディオデータはモノラルの場合とマルチチャネル (ステレオなど) の場合があることです。一方、物理ミキサーの入力と出力はそれぞれ、通常は単一チャネルのサウンドです。物理ミキサーから複数の出力チャネルを取り出すには、通常は複数の物理出力が使われます (少なくともアナログサウンドの場合。デジタル出力ジャックはマルチチャネルの場合が多い)。Java Sound API では、1 つのライン内のチャネルの数は、そのラインを流れているデータの AudioFormat
によって指定されます。
ここで、ラインとミキサーについて、いくつかの種類を挙げて考えてみます。次の図は、Java Sound API の実装の一部として使用できる、簡単なオーディオ出力システム内の数種類のラインを示します。
オーディオ出力用ラインの構成例この例では、アプリケーションプログラムはオーディオ入力ミキサーの使用可能な入力へのアクセス方法を持っています。それは、1 つまたは複数のクリップとソースデータラインです。クリップとは、オーディオデータをあらかじめロードしてから再生できるミキサー入力 (ラインの一種) です。ソースデータラインは、オーディオデータのリアルタイムのストリームを受け取るミキサー入力です。アプリケーションプログラムはサウンドファイルからクリップにオーディオデータをあらかじめロードします。次に、アプリケーションプログラムはその他のオーディオデータを、1 回に 1 バッファー分ずつソースデータラインに送ります。各ラインにはリバーブ、ゲイン、パンのコントロールがあります。ミキサーはすべてのラインからデータを読み込み、ドライのオーディオ信号とリバーブをかけたウェットのオーディオ信号をミキシングします。ミキサーは、スピーカー、ヘッドフォンジャック、ラインアウトジャックなどの 1 つ以上の出力ポートに最終的な出力を配信します。
この図ではさまざまなラインが個別の矩形で表されていますが、これらはすべてミキサーによって所有されており、ミキサーの一部と考えることができます。リバーブ、ゲイン、およびパンの矩形は、ラインを流れているデータに対してミキサーが実行する処理コントロールを表すもので、ラインではありません。
これは、この API でサポートできるミキサーの一例です。すべてのオーディオ構成に、図で示されているすべての機能があるわけではありません。個々のソースデータラインでパンをサポートしない場合や、ミキサーがリバーブを実装しない場合などもあります。
ここでは、データは 1 つ以上の入力ポート (通常はマイクロフォンまたはライン入力ジャック) からミキサーに流れます。ゲインとパンが適用され、ミキサーはミキサーのターゲットデータラインを経由して、取り込んだデータをアプリケーションプログラムに配信します。ターゲットデータラインは、ストリーミングされた入力サウンドの混合が含まれるミキサー出力です。もっとも単純なミキサーのターゲットデータラインは 1 つだけですが、取り込んだデータを同時に複数のターゲットデータラインに配信できるミキサーもあります。
ここまではラインとミキサーについて、機能面からいくつか見てきましたが、ここからは、プログラムの視点からの考察を行います。いくつかのラインは、基本インタフェース Line
のサブインタフェースによって定義されています。インタフェースの階層を次に示します。
基本インタフェース Line
には、すべてのラインに共通する最小限の機能が記述されています。
Line
のサブインタフェースはその他の種類のイベントを発行できます。ラインがイベントを生成すると、そのライン上でイベントが発生するまで「待機」するよう登録されたすべてのオブジェクトにそのイベントが送信されます。アプリケーションプログラムはこれらのオブジェクトを作成し、ラインイベントが発生するまで待機するよう登録し、必要に応じてそのイベントに応答することができます。
Line
インタフェースのサブインタフェースについて考えます。
Ports
は、オーディオ装置へオーディオを入力し、または装置からオーディオを出力する単純なラインです。すでに説明したとおり、一般的なポートの種類には、マイクロフォン、ライン入力、CD-ROM ドライブ、スピーカー、ヘッドフォン、ライン出力などがあります。
Mixer
インタフェースは当然ミキサーを表し、すでに説明したようにハードウェアデバイスまたはソフトウェアデバイスです。Mixer
インタフェースは、ミキサーのラインを取得するためのメソッドを提供します。ミキサーのラインには、オーディオをミキサーに送り込むソースラインと、ミキサーがミキシング済みのオーディオを送り出すターゲットラインがあります。オーディオ入力ミキサーの場合、ソースラインはマイクロフォン入力などの入力ポートで、ターゲットラインはオーディオをアプリケーションプログラムに送る TargetDataLines
(このあとで説明) です。一方、オーディオ出力ミキサーの場合、ソースラインはアプリケーションプログラムがオーディオデータを送り込む Clips
か SourceDataLines
(このあとで説明) で、ターゲットラインはスピーカーなどの出力ポートです。
Mixer
は、1 つ以上のソースラインと 1 つ以上のターゲットラインを持つものと定義されます。この定義によれば、ミキサーは実際にデータをミキシングしなくても構わないので、ミキサーのソースラインが 1 本だけという可能性もあります。Mixer
API はさまざまなデバイスを包含するためのものですが、通常は、この API でミキシングがサポートされています。
Mixer
インタフェースでは同期がサポートされるので、複数のミキサーのラインを同期グループとして扱うよう指定できます。指定後は、各ラインを個別に制御する必要はなく、グループのラインのどれかに単一のメッセージを送ることにより、グループのすべてのデータラインを開始、停止、またはクローズすることができます。この機能を持つミキサーを使うと、ライン間でサンプル精度の同期が得られます。
ジェネリック Line
インタフェースには、再生と録音の開始と停止を行う手段はありません。そのためには、データラインが必要です。DataLine
インタフェースは、Line
の機能以外に次の補足的なメディア関連機能を提供します。
START
および STOP
イベントが生成されます。 TargetDataLine
は、ミキサーからオーディオデータを受け取ります。通常、ミキサーはマイクロフォンなどのポートからオーディオデータを取り込んでいるため、ターゲットラインのバッファーにデータを置く前に、取り込んだオーディオを処理またはミキシングできます。TargetDataLine
インタフェースは、ターゲットデータラインのバッファーからデータを読み込むためのメソッド、および現在読み込みが可能なデータ量を特定するためのメソッドを提供します。
SourceDataLine
は、再生用のオーディオデータを受け取ります。これは、再生用にソースデータラインのバッファーにデータを書き込むためのメソッド、およびラインがブロックされずに受け取る用意ができているデータ量を特定するためのメソッドを提供します。
Clip
は、再生前にオーディオデータをロードできるデータラインです。データはストリーミングではなく事前にロードされるため、クリップのデュレーションが再生前にわかり、メディア内での開始位置を任意に選択できます。クリップはループできます。つまり、再生時に 2 つの指定したループ点間のすべてのデータを、指定した回数または無期限に繰り返すことができます。
この章では、サンプリングオーディオ API の重要なインタフェースとクラスのほとんどについて説明しました。次章からは、これらのオブジェクトをアプリケーションプログラムからアクセスして使用する方法について説明します。