< 目次

第2章: Sampledパッケージの概要

 

  1. Direct Audioミキサーは常にWindowsのデフォルトです。Solarisオーディオ・ミキサーが有効な場合は、Solarisのデフォルトです(Solarisマニュアルのミキサーに関するページを参照)。Linuxでは、ミキシングをサポートするデバイスがある場合にだけデフォルトになります。
  2. 理由としては、Direct Audioミキサーは「直接」であることから、SAMPLE_RATEコントロールをサポートしないためです。
  3. デフォルトのミキサーは、sound.propertiesファイルを使用して選択できます。

この章では、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にはさまざまなオーディオ・データ形式間での変換用のメソッドと、一般的な種類のサウンド・ファイルの読み込み/書込み用のメソッドが提供されています。ただし、これは包括的なサウンドファイル・ツールキットを目指すものではありません。特定の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オブジェクトで表されます。このオブジェクトには次の属性があります。

PCMは音の波形のエンコーディング手法の1つです。Java Sound APIには、振幅の線形量子化を使うものと符号付き/符号なしの整数値を使うものの2種類のPCMエンコーディングがあります。線形量子化とは、各サンプル内に保存されている数値がその瞬間の元の音圧に正比例し(ひずみは除外)、同様にその瞬間の音で振動するスピーカや鼓膜の変位に比例することを意味します。たとえば、コンパクト・ディスクは線形PCMエンコーディング・サウンドを使用します。mu-lawエンコーディングとa-lawエンコーディングは一般的な非線形エンコーディングで、オーディオ・データをより小さく圧縮することができます。これらのエンコーディング手法は、通常、電話や発話の録音に使用されます。非線形エンコーディングでは非線形関数を使って、元の音声の振幅を内部値にマップします。この関数は、ボリュームの大きい音より小さい音に、より高い振幅分解能を持たせるように設計することができます。

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インタフェースの階層

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

次に、Lineインタフェースのサブインタフェースについて考えます。

Portsは、オーディオ装置へオーディオを入力し、または装置からオーディオを出力する単純なラインです。すでに説明したとおり、一般的なポートの種類には、マイクロフォン、ライン入力、CD-ROMドライブ、スピーカ、ヘッドフォン、ライン出力などがあります。

Mixerインタフェースは当然ミキサーを表し、すでに説明したようにハードウェア・デバイスまたはソフトウェア・デバイスです。Mixerインタフェースは、ミキサーのラインを取得するためのメソッドを提供します。ミキサーのラインには、オーディオをミキサーに送り込むソース・ラインと、ミキサーがミキシング済みのオーディオを送り出すターゲット・ラインがあります。オーディオ入力ミキサーの場合、ソース・ラインはマイクロフォン入力などの入力ポートで、ターゲット・ラインはオーディオをアプリケーション・プログラムに送るTargetDataLines (このあとで説明)です。一方、オーディオ出力ミキサーの場合、ソース・ラインはアプリケーション・プログラムがオーディオ・データを送り込むClipsSourceDataLines (このあとで説明)で、ターゲット・ラインはスピーカなどの出力ポートです。

Mixerは、1つ以上のソース・ラインと1つ以上のターゲット・ラインを持つものと定義されます。この定義によれば、ミキサーは実際にデータをミキシングしなくても構わないので、ミキサーのソース・ラインが1本だけという可能性もあります。Mixer APIはさまざまなデバイスを包含するためのものですが、通常は、このAPIでミキシングがサポートされています。

Mixerインタフェースでは同期がサポートされるので、複数のミキサーのラインを同期グループとして扱うよう指定できます。指定後は、各ラインを個別に制御する必要はなく、グループのラインのどれかに単一のメッセージを送ることにより、グループのすべてのデータ・ラインを開始、停止、またはクローズすることができます。この機能を持つミキサーを使うと、ライン間でサンプル精度の同期が得られます。

ジェネリックLineインタフェースには、再生と録音の開始と停止を行う手段はありません。そのためには、データ・ラインが必要です。DataLineインタフェースは、Lineの機能以外に次の補足的なメディア関連機能を提供します。

TargetDataLineは、ミキサーからオーディオ・データを受け取ります。通常、ミキサーはマイクロフォンなどのポートからオーディオ・データを取り込んでいるため、ターゲット・ラインのバッファにデータを置く前に、取り込んだオーディオを処理またはミキシングできます。TargetDataLineインタフェースは、ターゲット・データ・ラインのバッファからデータを読み込むためのメソッド、および現在読込みが可能なデータ量を特定するためのメソッドを提供します。

SourceDataLineは、再生用のオーディオ・データを受け取ります。これは、再生用にソース・データ・ラインのバッファにデータを書き込むためのメソッド、およびラインがブロックされずに受け取る用意ができているデータ量を特定するためのメソッドを提供します。

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

この章では、サンプリング・オーディオAPIの重要なインタフェースとクラスのほとんどについて説明しました。次章からは、これらのオブジェクトをアプリケーション・プログラムからアクセスして使用する方法について説明します。

 


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