サウンドアーキテクチャの概要

設計目標

Java Sound API は、音声メディアの入出力への効果と制御のための低レベル API です。この API を使用すると、拡張性および柔軟性を向上させるフレームワークで、オーディオ入出力に通常必要な機能に対する明示的な制御を提供します。

サウンドはもっとも基本的な要素であるため、Java Sound は幅広いユーザのニーズに対応しています。Java Sound API は、たとえば次のような領域のアプリケーションに適用されます。

Java Sound を使うと、専門化された機能によってアプリケーションのオーディオサポートを拡張し、より高レベルのインタフェースおよびほかの種類のメディアとの統合性を提供するアーキテクチャをアプリケーションに統合することができます。

Java Sound は、Java プラットフォーム上でのもっとも低いレベルのオーディオサポートを提供します。これにより、オーディオ固有の機能を高度に制御できます。たとえば、デジタルオーディオや MIDI (Musical Instrument Digital Interface) デバイスなどのシステムリソースのインストール、アクセス、および操作を行うための機構が提供されます。Java Sound に高性能のサウンドエディタや GUI ツールが含まれているのではなく、Java Sound はそのようなアプリケーションの構築を可能にする機能のセットを提供しています。Java Sound は、エンドユーザが一般的に必要とするよりもさらに低レベルの制御に重点を置いています。エンドユーザは、Java Sound を基に構築された高レベルのインタフェースを利用できます。

注 - このドキュメントでは、「アプリケーション」という用語は、通常 Java アプレットと Java アプリケーションを指します。

 

パッケージ

Java Sound API には、デジタルオーディオと MIDI データの両方をサポートする機能が含まれています。これらの主な 2 つの機能のモジュールは、別々のパッケージで提供されます。

javax.sound.sampled
このパッケージでは、デジタル (サンプリング) オーディオの取り込み、ミキシング、および再生のためのインタフェースを指定しています。

javax.sound.midi
このパッケージでは、MIDI 合成、シーケンシング、およびイベント転送のためのインタフェースを提供しています。

このほかに、次の 2 つのパッケージによって、サービスプロバイダ (アプリケーション開発者と対立する立場) が、システム上にインストールできるカスタムコンポーネントを作成できるようになります。

javax.sound.sampled.spi
javax.sound.midi.spi

このドキュメントの次の節で、javax.sound.sampled API の概要など、サンプリングオーディオシステムについて説明します。 最後の節で、MIDI システムおよび javax.sound.midi API について説明します。

サンプリングオーディオ

javax.sound.sampled パッケージは、デジタルオーディオデータを処理します。デジタルオーディオデータは、サンプリングオーディオとも呼ばれます。(「サンプル」とは、信号の連続するスナップショットのことです。デジタルオーディオの場合は音波です。たとえば、コンパクトディスクに保存するために録音されるオーディオは、1 秒間に 44,100 回サンプリングされます。通常、サンプリングオーディオはサウンドの録音によって作成されますが、サウンドを合成して生成することもできます。「サンプリングオーディオ」という用語は、データの種類を表し、データの出所を表すものではありません。サンプリングオーディオは、サウンド自体と考えることができますが、MIDI データは、音楽サウンドを作成するためのレシピであると考えることができます。)

Java Sound は、特定のオーディオハードウェア構成を想定していません。システム上にさまざまな種類のオーディオコンポーネントをインストールできるように設計されており、それらには API を使ってアクセスできます。Java Sound は、サウンドカードに対する入出力 (サウンドファイルの録音や再生など)、オーディオの複数のストリームのミキシングなど、一般的な機能をサポートしています。Java Sound を利用できる一般的なオーディオアーキテクチャの例を以下に示します。

一般的なオーディオアーキテクチャ

この例では、サウンドカードなどのデバイスにさまざまな入出力ポートがあり、ミキシングはソフトウェア内で提供されます。ミキサーのオーディオ入力の 1 つとして示されている MIDI シンセサイザは、サウンドカードの機能でも、ソフトウェア内に実装されているものでも構いません。(あとで説明する javax.sound.midi パッケージは、シンセサイザ用の Java インタフェースを提供します。)

次の節では、javax.sound.sampled パッケージで使われている主な概念について説明します。



ライン

ラインとは、オーディオ入出力ポート、ミキサー、オーディオデータとミキサー間のデータの経路など、デジタルオーディオの「パイプライン」となる要素です。ラインを流れるオーディオデータは、モノチャネルの場合とマルチチャネル (ステレオなど) の場合があります。各種のラインについて簡単に説明します。まず、これらの機能の関係について、「パイプライン」上でのオーディオの流れを示す図を使って説明します。次の図は、単純なオーディオ出力システム内のいくつかの種類のラインを示します。

オーディオ出力用ラインの構成例

この例では、アプリケーションはミキサーに対して、利用可能な 1 つ以上のクリップとソースデータラインを要求しました。クリップは、再生前にオーディオデータをロードできるミキサー入力です。ソースデータラインは、オーディオデータのリアルタイムのストリームを受け入れるミキサー入力です。アプリケーションはサウンドファイルからクリップにオーディオデータをプリロードしてから、ほかのオーディオデータをソースデータラインに入れます。ミキサーは、これらのラインからデータを読み込みます。各ラインに、独自のリバーブ、ゲイン、およびパンのコントロールがある場合があります。ミキサーは、リバーブの設定を使って、「ドライ」のオーディオ信号とリバーブをかけた「ウェット」のオーディオ信号をミキシングすることができます。ミキサーは、スピーカ、ヘッドフォンジャック、ラインアウトジャックなどの 1 つ以上の出力ポートに最終的な出力を配信します。

この図ではさまざまなラインが個別の矩形で表されていますが、これらはすべてミキサーによって所有されており、ミキサーの一部と考えることができます。リバーブ、ゲイン、およびパンの矩形は、ラインを流れているデータに対してミキサーが実行する処理コントロールを表すもので、ラインではありません。(これは、API によってサポートされるオーディオシステムの一例に過ぎません。すべてのオーディオ構成に、図で示されているすべての機能があるわけではありません。個々のソースデータラインでパンをサポートしていない場合や、ミキサーがリバーブを実装していない場合などもあります。)

単純なオーディオ入力システムも同様です。

オーディオ入力用ラインの構成例

ここでは、データは 1 つ以上の入力ポート (通常はマイクロフォンまたはラインインジャック) からミキサーに流れます。ゲインとパンが適用され、ミキサーはミキサーのターゲットデータラインを経由して、取り込んだデータをアプリケーションに配信します。ターゲットデータラインは、ストリーミングされた入力サウンドの混合が含まれるミキサー出力です。もっとも単純なミキサーのターゲットデータラインは 1 つだけですが、取り込んだデータを同時に複数のターゲットデータラインに配信できるミキサーもあります。

ここでは、さまざまな種類のラインをより詳しく見てみます。いくつかのラインは、基本インタフェース Line のサブインタフェースによって定義されています。インタフェースの階層を次に示します。

Line インタフェースの階層

基本インタフェース Line には、すべてのラインに共通する最小限の機能が記述されています。

Port は、オーディオデバイスに対するオーディオの入力または出力のための単純なラインです。Port インタフェースは、ポートの種類を指定する内部クラス Port.Info を持ちます。一般的な種類として、マイクロフォン、ライン入力、CD-ROM ドライブ、スピーカ、ヘッドフォン、ライン出力などがあります。

Mixer インタフェースは、1 つ以上の入力ラインと 1 つ以上の出力ラインを持つハードウェアまたはソフトウェアデバイスを表します。これは、ミキサーが実際にはデータをミキシングする必要がないことを意味します。ミキサーに単一入力しかない可能性があります。Mixer API はさまざまなデバイスを包含するためのものですが、通常は、この API でミキシングがサポートされています。

Mixer インタフェースは、ミキサーのラインを取得するためのメソッドを提供します。これらのメソッドには、ターゲットデータラインが含まれます。ターゲットデータラインからは、アプリケーションが取り込まれたオーディオデータ、ソースデータライン、およびクリップを読み込むことができます。ソースデータラインには、アプリケーションが再生 (レンダリング) のためにオーディオデータを書き込むことができます。クリップ内には、アプリケーションが再生のためにサウンドデータをプリロードできます。ミキサーは、これらのリソースをロックできます。たとえば、ミキサーにターゲットデータラインが 1 つしかなく、すでに使用されている場合は、アプリケーションがターゲットデータラインを取得しようとすると、例外がスローされます。

Line.Info の適切な種類を渡すことによって、ミキサーに別の種類のラインを問い合わせることができます。また、ミキサーに対して、ミキサーがサポートする特定の種類のラインの数を問い合わせることもできます。

ミキサーは、Mixer.Info という内部クラス内に、特定の種類のデバイスについてのテキスト情報を保持します。この情報には、製品名、バージョン、およびベンダー名がテキストによる説明とともに含まれています。

汎用の Line インタフェースは、再生または録音の開始および停止を行う機能を提供しません。そのためには、データラインが必要です。DataLine インタフェースは、Line の機能以外に次の補足的なメディア関連機能を提供します。

アプリケーションは、ミキサーからデータラインを取得できます。リソースの制約 (ミキサーがサポートする唯一のターゲットデータラインがすでに使用されているなど) によりデータラインが割り当てられない場合は、例外がスローされます。

TargetDataLine は、ミキサーからオーディオデータを受け取ります。通常、ミキサーはマイクロフォンなどのポートからオーディオデータを取り込んでいるため、ターゲットラインのバッファにデータを置く前に、取り込んだオーディオを処理またはミキシングできます。TargetDataLine インタフェースは、ターゲットデータラインのバッファからデータを読み込むためのメソッド、および現在読み込みが可能なデータ量を特定するためのメソッドを提供します。アプリケーションが読み込み可能な量以上のデータを読み込もうとすると、要求された量のデータが読み込み可能になるまで読み込みメソッドがブロックされます。これは、要求されたデータ量がラインのバッファサイズよりも多い場合にも適用されます。この読み込みメソッドは、ラインがクローズ、一時停止、またはフラッシュされているかどうかを返します。

オーディオを録音しているアプリケーションは、バッファがオーバーフローしないように十分な速度でターゲットデータラインからデータを読み込む必要があります。バッファのオーバーフローにより、取り込んだデータが不連続になります。バッファがオーバーフローした場合は、キュー内のもっとも古いデータが破棄され、新しいデータと置き換えられます。

SourceDataLine は、再生用のオーディオデータを受け取ります。SourceDataLine は、再生用にソースデータラインのバッファにデータを書き込むためのメソッド、およびラインがブロックされずに受け取る用意ができているデータ量を特定するためのメソッドを提供します。アプリケーションが書き込み可能な量以上のデータを書き込もうとした場合は、要求された量のデータが書き込み可能になるまで読み込みメソッドがブロックされます。これは、要求されたデータ量がラインのバッファサイズよりも多い場合にも適用されます。この書き込みメソッドは、ラインがクローズ、一時停止、またはフラッシュされているかどうかも返します。

オーディオを再生しているアプリケーションは、バッファがアンダーフローしない (空にならない) ように十分な速度でソースデータラインにデータを書き込む必要があります。バッファのアンダーフローにより、オーディオの再生が不連続になります。アンダーフローのために再生が停止した場合は、STOP イベントが生成されます。再生が再開されると START イベントが生成されます。

Clip は、再生前にオーディオデータをロードできるデータラインです。データはストリーミングではなくプリロードされるため、クリップのデュレーションが再生前にわかり、メディア内での開始位置を任意に選択できます。クリップはループできます。つまり、再生時に 2 つの指定したループ点間のすべてのデータを、指定した回数または無期限に繰り返すことができます。

GroupLine は、データラインの同期化されたグループです。ミキサーがグループラインをサポートする場合は、グループとして扱うデータラインを指定できます。指定後は、各ラインを個別に制御する必要はなく、グループにメッセージを 1 つ送信することによってこれらすべてのデータラインを開始、停止、またはクローズすることができます。



コントロール

データラインおよびポートは、多くの場合、ラインを通るオーディオ信号に作用するコントロールのセットを持っています。コントロールの種類によって、信号への作用が異なります。Java Sound API は、Control の次のサブクラスを定義します。

プログラムに基づいて、特定のコントロールオブジェクトは、コントロールのクラスへの参照によってラインから取得します。そのラインのすべてのコントロールの配列を取得することもできます。



AudioSystem

AudioSystem クラスは、インストールされているサンプリングオーディオリソースにアクセスするためのアプリケーションのエントリポイントになります。AudioSystem に問い合わせてインストールされているオーディオコンポーネントを調べ、それらのコンポーネントへのアクセスを取得できます。たとえば、アプリケーションは、ラインの説明の節で図解した入力または出力の構成など、特定の構成を持つミキサーがあるかどうかを AudioSystem に問い合わせることから始めることができます。アプリケーションは、その後、ミキサーからデータラインを取得するなどの処理を行うことができます。

アプリケーションが AudioSystem から取得できるリソースの例を以下に示します。



システム構成 (SPI クラス)

サンプリングオーディオシステム用のサービスプロバイダインタフェースは、javax.sound.sampled.spi パッケージ内で定義されています。サービスプロバイダは、ここに定義されているクラスを拡張して、独自のオーディオデバイス、サウンドファイルパーサとライター、および形式コンバータをインストールし、Java Sound の実装によって利用できるようにすることができます。



MIDI

MIDI イベントの転送、合成、およびシーケンシングを記述するインタフェースは、javax.sound.midi パッケージ内で定義されています。このパッケージ内で使用されている概念の中心的な部分を以降の節で説明します。



機能概要

下の図に、一般的な Java Sound MIDI 構成内の主なコンポーネント間の機能の関係を示します。(Java Sound では、さまざまなデバイスのインストールおよび相互接続が可能です。ここで示すシステムは、一例に過ぎません。)コンポーネント間のデータの流れは、矢印で示してあります。データは、標準のファイル形式のデータにすることも、図の右下隅に一覧で示されているように、オーディオ、raw MIDI バイト、または Java Sound の MidiEvent オブジェクトにすることも可能です。

一般的な MIDI 構成

この例では、アプリケーションは、ディスク上に標準 MIDI ファイルとして保存されている楽譜をロードして音楽の演奏の準備をします (図の左下隅)。標準 MIDI ファイルには、トラックが含まれています。それぞれのトラックは、時刻のタグが付いた MIDI イベントのリストです。この MIDI ファイルは、Sequence オブジェクトに読み込まれ、オブジェクトのデータ構造にファイルが反映されます。Sequence には Track オブジェクトのセットが含まれ、各セットには MidiEvent オブジェクトのセットが含まれます。Sequence は、次に、Sequencer によって「演奏」されます。Sequencer は、内部または外部のシンセサイザなどのほかのデバイスに MidiEvents を送信することによって音楽の演奏を行います。

図に示すとおり、MidiEvents は、MIDI 出力ポートを使って外部のシンセサイザに送信される前に、時刻のタグが付いた raw MIDI に変換される必要があります。この変換は、StreamGenerator という MIDI 出力デバイスによって行われます。同様に、外部の MIDI ソースからコンピュータに入る raw MIDI データは、StreamParser によって MidiEvents に変換されます。

内部のシンセサイザ (図で「Synthesizer」と記されている矩形) は、Sequencer または StreamParser から直接 MidiEvents を受け入れます。内部シンセサイザは、各イベントを解析し、通常は、イベント内に指定された MIDI チャネル番号に応じて MidiChannel オブジェクトの 1 つに対応するコマンド (noteOn など) をディスパッチします。(MIDI 仕様で 16 の MIDI チャネルが要求されるので、通常は Synthesizer は 16 の MidiChannel オブジェクトを持っています。)

MidiChannel は、これらのメッセージ内の音情報を使って音楽を合成します。たとえば、noteOn メッセージは、ノートのピッチおよび「ベロシティ」(ボリューム) を指定します。ただし、この音情報は十分ではありません。シンセサイザには、各音に対してオーディオ信号を作成する方法についての正確な指示も必要です。これらの指示は、Instrument によって表されます。通常、各 Instrument は、実際にある楽器またはサウンドエフェクトをエミュレートします。Instruments は、シンセサイザであらかじめ設定されているようにすることも、サウンドバンクファイルからロードするようにすることも可能です。シンセサイザでは、Instruments は、バンク番号 (図中の行) およびプログラム番号 (列) によって整理されます。Instrument は、サウンドバンク内に Sample オブジェクトとして保存されているデジタルオーディオを利用できます。たとえば、5 秒間の長さのトランペットの音を再生するには、シンセサイザは、トランペットの録音の半秒の断片をループ (反復) させることができます。

これまでは機能的な観点からコンポーネントを説明してきましたが、ここではプログラミングの観点からこの API について簡単に考察します。



MidiEvent

MidiEvent オブジェクトは、このオブジェクトがラッパーとなる raw MIDI メッセージの種類、データ長、およびステータスバイトを指定します。また、シーケンサなどの MIDI のタイミングに関連するデバイスによって使われる時間値も提供します。

イベントのカテゴリは 3 つあり、それぞれ MidiEvent サブクラスによって表されます。



MidiDevice

デバイスの基本インタフェースは MidiDevice です。すべてのデバイスは、サポートする MIDI モードのセットを一覧表示するためのメソッド、および現在のモードの問い合わせおよび設定を行うためのメソッドを提供します。(モードは、MIDI の Omini モードおよび Mono/Poly モードの組み合わせです。)デバイスは、オープンおよびクローズが可能で、MidiDevice.Info オブジェクトを使ってデバイス自体の説明を提供します。

次の図に MidiDevice インタフェースの階層を示します。また、MidiDevice インタフェースが実装し、それらのインタフェースに破線で結ばれている 2 つのクラスも示します。

MidiDevice の階層

デバイスは、一般に MidiEvents のトランスミッタまたはレシーバです。MidiDeviceTransmitter サブインタフェースには、トランスミッタが MidiEvents を送信するレシーバの設定およびレシーバへの問い合わせを行うための複数のメソッドが含まれます。トランスミッタ側から見ると、これらのレシーバは 2 つのカテゴリ MITI Out と MIDI Thru に分類されます。トランスミッタは、トランスミッタ自体が生成するイベントを MIDI Out レシーバに送信します。トランスミッタ自体がレシーバである場合は、トランスミッタは、ほかから受け取ったイベントを、トランスミッタ自体の MIDI Thru レシーバに渡します。 MidiDeviceReceiver サブインタフェースには、MidiEvents を受け取るための 1 つのメソッドが含まれています。このメソッドは通常、Transmitter によって呼び出されます。

Java Sound には、MidiEvent オブジェクトと MIDI ワイヤプロトコルで使われる raw バイトストリーム間の変換のための具象クラスが含まれています。StreamGeneratorは、Transmitter からの MidiEvent オブジェクトを受け取り、raw MIDI バイトストリームを書き出す Receiver です。同様に、StreamParser は、raw MIDI バイトストリームを受け取り、対応する MidiEvent オブジェクトを Receiver に書き込む Transmitter です。



合成

Synthesizer は、サウンドを生成する MidiDevice の一種です。Synthesizer インタフェースは、ReceiverTransmitter の両方を拡張します。このインタフェースは、サウンドバンクおよび楽器を操作するためのメソッドを提供します。さらに、サウンドの実際の生成に使われる MIDI チャネルのセットへのアクセスも提供します。Synthesizer は、MidiEvents を受け取り、対応する MidiChannel メッセージを呼び出します。

MidiChannels は、「ノートオン」や「コントロールチェンジ」などの一般的な MIDI ボイスメッセージを表すメソッドを持っています。MidiChannelsは、チャネルの現在の状態の問い合わせも許可します。



シーケンシング

Synthesizer と同様に、Sequencer インタフェースは、TransmitterReceiver の両方 (したがって MidiDevice) を拡張します。Sequencer は、基本的な MIDI シーケンシング操作のためのメソッドを追加します。シーケンサにより、シーケンスのロードと再生、テンポの問い合わせと設定、およびマスターとスレーブの同期モードの制御が可能です。アプリケーションは、シーケンサが MetaEvents およびコントローライベントを処理したときに通知されるように登録できます。(コントローライベントは、ピッチベンドのホイールやデータスライダなどの MIDI コントローラの値が変わったときに発生します。これらのイベントは、MidiEvents ではなく、SequencerSequence 内で特定の ShortEvents を検出した場合に作成されます。)

Sequence オブジェクトは、 MIDI シーケンスを 1 つ以上のトラックおよび関連するタイミング情報で表します。トラックには、タイムスタンプが付いた MIDI イベントのリストが含まれます。シーケンサは、MIDI ファイルから読み込むことも、ゼロから作成することも可能で、SequenceTracks を追加 (または削除) することによって編集できます。同様に MidiEvents は、Tracks に追加することも Tracks から削除することもできます。

トラックには、タイムスタンプが付いた MIDI イベントのリストが含まれます。シーケンサは、MIDI ファイルから読み込むことも、ゼロから作成することも可能で、SequenceTracks を追加 (または削除) することによって編集できます。同様に MidiEvents は、Tracks に追加することも Tracks から削除することもできます。

ファイルの再生前に、MIDI ファイルを Sequence オブジェクトにロードする必要はありません。SequencersetSequence(java.io.InputStream) メソッドを使うと、最初に Sequence オブジェクトを作成しなくても、MIDI ファイルを直接 Sequencer に読み込むことができます。



MidiSystem

MidiSystem は、MIDI 音楽システムへのアプリケーションのエントリポイントになります。MidiSystem により、トランスミッタ、レシーバ、シンセサイザ、シーケンサなど、インストールされているデバイスのセットについての情報と、それらへのアクセスが提供されます。

MidiSystem クラスは、MIDI ファイルを読み込んで Sequence オブジェクトを作成するためのメソッド、および MIDI ファイルに Sequences を書き込むためのメソッドを提供します。MIDI Type 0 ファイルにはトラックが 1 つしか含まれませんが、Type 1 ファイルには任意の数のトラックが含まれる場合があります。MidiSystem は、サウンドバンクファイルの解析によって Soundbank オブジェクトを作成するためのメソッドも提供します。



システム構成 (SPI インタフェース)

MIDI システムの構成は、 javax.sound.midi.spi package で処理されます。このパッケージ内の抽象クラスにより、サービスプロバイダは、独自の MIDI デバイス、 MIDI ファイルリーダおよびライター、サウンドバンクファイルリーダを提供およびインストールできます。


Copyright © 1999 Sun Microsystems, Inc. All Rights Reserved.

コメントの送付先:mailto:javasound-comments@javamedia.eng.sun.com
Sun
Java ソフトウェア