アプリケーションは、ハードウェア抽象化層(HAL)のAudioOutputUnitを使って、単一のオーディオデバイスとインターフェイスをとることができます。AudioOutputUnit (AUHAL)ユニットは、<CoreAudio/AudioHardware.h>で定義されている AUHALを使ってオーディオデバイスから入力を取り込むには、以下の手順に従ってください。 1.AUHALを開きます。 2.AUHALの入力を使用可能にします。 3.デフォルトの入力デバイスをAUHALのカレント入力デバイスに設定します。 4.デバイスフォーマットを取得し、希望のオーディオフォーマットを指定します。 5.入力コールバックを作成し、AUHALに登録します。 6.必要なバッファを割り当てます。 7.AUHALを初期化して開始します。 これらの手順について、このテクニカルノートで詳しく説明します。 AudioOutputUnitの作成まず、他のAudio Unitを取得する場合と同様に、Component Descriptionを使って、まずAudioOutputUnitを取得する必要があります。 リスト1: AudioOutputUnitを開く方法
Component comp;
ComponentDescription desc;
// 数種類のAudio Unitがある。
// いくつかのAudio Unitは入力、ミキサー、またはDSPユニットとして機能する。
// 一覧については、AUComponent.hを参照。
desc.componentType = kAudioUnitType_Output;
// すべてのコンポーネントはsubTypeを持っており、これがコンポーネントの機能を
// 明確に記述する。
desc.componentSubType = kAudioUnitSubType_HALOutput;
// AUComponent.hに記載されたすべてのAudio Unitは、
//"kAudioUnitManufacturer_Apple"をManufacturerとして使用する必要がある。
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
// descのスペックに合ったコンポーネントを検出する。
comp = FindNextComponent(NULL, &desc);
if (comp == NULL) exit (-1);
// コンポーネントの提供するサービスにアクセスする。
OpenAComponent(comp, &InputUnit);
Audio Unit接続の概要Audio Unitは、異なる2つのAudio Unit間の直接接続の概念を具現化しています。Audio Unitはデータを生成するように要求されると、コールバック関数または接続されている別のAudio Unitからデータを受け取ることができます。接続の例として、A1とA2という2つのAudio Unitがあれば、A1をA2に接続します(A1-->A2)。A2がデータを生成するように要求されると、データストリームは基本的にA1からA2へ「プル」されて処理されます。そのため、Audio Unit間の接続は、同じオーディオストリームフォーマットを共有する必要があります。Audio Unitと接続の詳細については、『Audio and MIDI on Mac OS X』 を参照してください。 図1: AUHALのシグナルフロー
図1は、オーディオデバイスとアプリケーション間のオーディオデータのフローを示しています。アプリケーションは処理を単純化するために、Audio UnitをAUHALのいずれかの要素(バス)に接続できます。つまり、デバイスにオーディオを出力するソースとしてAudio Unitを使う場合は、次の接続を使用します。 表1: デバイスへのオーディオ出力
オーディオデバイスの入力データを取得したい場合は、次のように接続します。 表2: デバイスへの音声取り込み
もちろん、入出力を提供する内蔵オーディオデバイスのようなデバイスについては、次の接続を作成することで、ソフトウェアプレイスルーのメカニズムを確立することができます。 表3: 簡単なソフトウェアプレイスルー
入出力の間に1つ以上のAudio Unitを挿入することにより、入力から出力まで、オーディオに必要な処理操作を何度でも実行できます。ここで、マルチバンドコンプレッサAudio Unitを使って内蔵オーディオ入力を処理する例を挙げてみましょう。これを行うには、次の接続を作成します。 表4: マルチバンドコンプレッサAudio Unitによる内蔵オーディオ入力の処理
これらの接続は(AudioToolbox.frameworkの)AUGraph APIで管理できます。 2つの別々のオーディオデバイスを使う場合は、2つのAUHALが必要となります。しかし、それぞれのAUHALは個別のI/Oプロセスで実行するため、2つのAUHALの間に直接の接続を確立できません。通知メカニズムを使用して、出力デバイスに対してデータが到着したことを通知し、データを渡す必要があります。 注: AUGraphごとに使用できるAudioOutputUnitは1つのみです。 IOの有効化AUHALオブジェクトを作成したら、デバイス入力を取得するために、Audio Unitの入力範囲にあるIOを使用可能にする必要があります。入力は、AUHALの要素 1にある リスト2: AudioOutputUnitの入力の有効化と出力の無効化
UInt32 enableIO;
UInt32 size=0;
// AudioUnitSetPropertyを使用する場合は、メソッドの4番目のパラメータが
// AudioUnitElementを参照する。AudioOutputUnitを使用する場合は、
// 入力要素を「1」にして、出力要素を「0」にする。
enableIO = 1;
AudioUnitSetProperty(InputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
1, // 入力要素
&enableIO,
sizeof(enableIO));
enableIO = 0;
AudioUnitSetProperty(InputUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
0, // 出力要素
&enableIO,
sizeof(enableIO));
AudioOutputUnitのカレントデバイスの設定AUHALには、インターフェイスをとるデバイスがなければなりません。この例では、カレントデバイスとしてシステムのデフォルト入力デバイスを選択します。 リスト3: AudioOutputUnitのカレントデバイスをデフォルト入力デバイスに設定する方法
OSStatus SetDefaultInputDeviceAsCurrent(){
UInt32 size;
OSStatus err =noErr;
size = sizeof(AudioDeviceID);
AudioDeviceID inputDevice;
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
&size,
&inputDevice);
if (err)
return err;
err =AudioUnitSetProperty(InputUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
0,
&inputDevice,
sizeof(inputDevice));
return err;
}
オーディオデータのフォーマットについてAUHALは、入出力ともに、デバイスのオーディオデータストリームを単一のインターリーブされていないストリームにフラット化します。AUHALには、この変換を実行する オーディオデバイスにデータを出力するには、フォーマットを必ずAUHALの要素 0の出力範囲で明示します。オーディオデバイスフォーマットを取得するには、 デバイスから入力を取得するには、デバイスフォーマットを必ずAUHALの要素 1の入力範囲で明示します。このため、希望のフォーマットはAUHAの要素 1の出力範囲に設定する必要があります。内部の リスト4: 希望する「入力」フォーマットの設定
CAStreamBasicDescription DeviceFormat;
CAStreamBasicDescription DesiredFormat;
// CAStreamBasicDescriptionsを「裸」の
// AudioStreamBasicDescriptionsの代わりに使うことでエラーを最小限にする。
// CAStreamBasicDescription.hはCoreAudio SDKに含まれている。
UInt32 size = sizeof(CAStreamBasicDescription);
// 入力デバイスフォーマットを取得する
AudioUnitGetProperty (InputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
1,
&DeviceFormat,
&size);
// 希望のフォーマットをデバイスのサンプルレートに設定する
DesiredFormat.mSampleRate = DeviceFormat.mSampleRate;
// フォーマットを出力範囲に設定する
AudioUnitSetProperty(
InputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
1,
&DesiredFormat,
sizeof(CAStreamBasicDescription);
チャネルマッピングオーディオデバイスのチャネルと希望フォーマットのチャネルのデータフォーマットが1:1の比率に対応していない場合は、チャネルマッピングが必要です。チャンルマッピングでは、Audio Unitがどんなデバイスチャネルと対話するかを指定します。これを設定する必要があるのは、デフォルトのマッピング以外の設定を使う予定がある場合に限られます。 表5: デフォルトのチャネルマップ(チャネルマッピングは不要)
たとえば、入力に使用する4チャネルのデバイスがあり、ステレオ入力としてデバイスの2または3チャネルのみが必要であったとします。必要なチャネルをAUHALのチャネルに割り当てる(マップする)必要があります。AUHALのチャネルマップを作成するには、マップの「出力先」ごとにSInt32の配列を作成する必要があります。Sint32の配列の各要素は、出力先に送られるソースチャネルのインデックス、または「ソースなし」を意味する-1を参照します。この例では、2つの要素の配列を作成し、その値を-1に初期設定します。マップしたいチャネルには、チャネルマップ配列の要素の値を2と3に設定します。その結果、チャネルマップは [2,3] になります。 表6: 4 -> 2チャネルマップ
リスト5: 入力用の4 -> 2チャネルマッピングの例
SInt32 *channelMap =NULL;
UInt32 numOfChannels = DesiredFormat.mChannelsPerFrame; // 2チャネル
UInt32 mapSize = numOfChannels *sizeof(SInt32);
channelMap = (SInt32 *)malloc(size);
// 必要な入力の各チャネルに、デバイスの出力チャネルから
// チャネルをマップする。
for(UInt32 i=0;i<numOfChannels;i++)
{
channelMap[i]=-1;
}
//channelMap[desiredInputChannel] = deviceOutputChannel;
channelMap[0] = 2;
channelMap[1] = 3;
AudioUnitSetProperty(InputUnit,
kAudioOutputUnitProperty_ChannelMap,
kAudioUnitScope_Output,
1,
channelMap,
size);
free(channelMap);
AudioOutputUnitの入力プロシージャの作成次に、AUHALの入力プロシージャを登録する必要があります。AUHALが入力デバイスから新しいデータを受け取ると、このプロシージャが呼び出されます。 リスト6: AudioOutputUnitの入力プロシージャの作成
void MyInputCallbackSetup()
{
AURenderCallbackStruct input;
input.inputProc = InputProc;
input.inputProcRefCon = 0;
AudioUnitSetProperty(
InputUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
0,
&input,
sizeof(input));
}
AudioOutputUnitの初期化と開始AUHALがデバイスから入力を受け取るように設定します。データの取得を開始するには、Audio Unitを初期化して開始する必要があります。 リスト7: AUHALの開始
OSStatus InitAndStartAUHAL()
{
OSStatus err= noErr;
err = AudioUnitInitialize(InputUnit);
if(err)
return err;
err = AudioOutputUnitStart(InputUnit);
return err;
}
AudioOutputUnitからのデータの取得AUHALは、オーディオデバイスとの間でオーディオデータを送受信できるAudio Unitです。AUHALからオーディオを受信するには、Audio Unitの出力範囲から取得する必要があります。実際には、これはクライアントが 下の例では、入力プロシージャ内から リスト8: AudioUnitRenderを使ったデータの取得
AudioBufferList * theBufferList;
/* バッファデータを保持するために割り当て */
OSStatus InputProc(
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
OSStatus err =noErr;
err= AudioUnitRender(InputUnit,
ioActionFlags,
inTimeStamp,
inBusNumber, // 入力データの '1' になる
inNumberFrames, // 必要なフレーム数
theBufferList);
return err;
}
まとめAUHALを使ってオーディオデバイスとインターフェイスをとると、アプリケーションとオーディオデバイス間の対話を大幅に簡素化できます。このAudio Unitは、オーディオデバイス情報の取得と、オーディオデータの転送や取得を行う際にオーディオデベロッパを支援します。 サンプルコード、参考資料、注意事項サンプルコード - RecordAudioToFileサンプルコード - ComplexPlayThru サンプルコード - SimplePlayThru Core Audio Preliminary doc Audio and MIDI on Mac OS X -May 2001 注: システムの条件:QuickTime v6.5をインストールしたMac OS X v10.2およびv10.3。 ドキュメント改訂履歴
掲載日: 2006-07-25 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|