高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technical Note TN2112
Using the 3DMixer Audio Unit

このテクニカルノートでは、Core Audio の 3DMixer Audio Unit バージョン 2.0 の使用法について説明します。

3DMixer Audio Unit は、いくつかの異なるソースのオーディオをミックスして、サウンドを立体空間で定位することができます。これは、複数のオーディオソースを単純かつ効率的に管理する必要のあるゲームやその他の多くの対話型アプリケーションで非常に役立ちます。このテクニカルノートは、3DMixer Audio Unit v2.0 の現在および新規ユーザを対象にしています。





3DMixer Audio Unit v2.0 には、サウンドを立体空間の中で定位する機能、すなわち、複数の音源を距離、仰角、および方位角によってリスナーの周囲に配置する機能があります。3DMixer は複数チャネルのレイアウト(「スピーカー設定」セクションで後述)を対象にレンダリングを行うことができます。さらに、再生中にレンダリングされるサウンドの品質は、CPU のパフォーマンス要求に合わせて調節することができます。

3DMixer 用の AUGraph の作成

The 3D Mixer

図 1: 3D Mixer

3DMixers はデータフローの管理を支援するために、通常、Audio Unit Graph (AUGraph) に挿入します。AUGraph は、一組の Audio Unit とそれらの間の接続を表す高水準の表現です。AUGraph API を使って、オーディオを処理する任意の信号パス、すなわちモジュール型ルーティングシステムを構築することができます。API は多数の AudioUnit とそれらの関係を処理します。

グラフの先頭は必ず出力ユニットであり、処理したオーディオストリームをディスクやメモリに、またはサウンド出力として保存することができます。グラフを開始すると、先頭オーディオユニット(データはここからグラフを出ます)が「プル」され、先頭オーディオユニットはグラフ内の接続されているオーディオユニットからデータをプルします。このテクニカルノートでは、グラフの先頭としてデフォルト出力オーディオユニットを使用します。デフォルト出力ユニットは、Audio MIDI 設定アプリケーションまたはシステム環境設定の出力パネルでユーザが選択した出力装置(多くの場合はスピーカー)になります。Audio Unit Graph の使い方の詳細については、「Using the Audio Toolbox」を参照してください。

グラフの設定を開始するには、AUGraphNewNode() メソッドを使って、3DMixer およびデフォルト出力 AudioUnit のノードを追加する必要があります。ノードを作成すると、グラフを開き、 AUGraphGetNodeInfo() メソッドを使って、グラフ内のノードから AudioUnit インスタンスを取得することができます。

リスト 1: AUGraph の作成とノードの追加

void MyCreateAUGraph(  AUGraph  mAUGraph,AudioUnit mOutputUnit,
 AudioUnit mMixerUnit)
{
    AUNode mMixerNode, mOutputNode;

    NewAUGraph(&mAUGraph);

    ComponentDescription    mixerCD;

    mixerCD.componentFlags = 0;
    mixerCD.componentFlagsMask = 0;
    mixerCD.componentType = kAudioUnitType_Mixer;
    mixerCD.componentSubType = kAudioUnitSubType_3DMixer;
    mixerCD.componentManufacturer = kAudioUnitManufacturer_Apple;

    AUGraphNewNode (mAUGraph, &mixerCD, 0, NULL, &mMixerNode);

    ComponentDescription    cd;
    cd.componentFlags = 0;
    cd.componentFlagsMask = 0;

    cd.componentType = kAudioUnitType_Output;
    cd.componentSubType = kAudioUnitSubType_DefaultOutput;
    cd.componentManufacturer = kAudioUnitManufacturer_Apple;

    AUGraphNewNode (mAUGraph, &cd, 0, NULL, &mOutputNode);

      //グラフを開く
     AUGraphOpen (mAUGraph);
       
     //グラフから Audio Unit を取得する
    AUGraphGetNodeInfo (mAUGraph, mMixerNode, 0, 0, 0, &mMixerUnit);
    AUGraphGetNodeInfo (mAUGraph, mOutputNode, 0, 0, 0, &mOutputUnit);
         
}

グラフが作成されたら、グラフを初期化して開始する前に、3DMixer を適切に設定する必要があります。

先頭に戻る

バスカウントの設定

3Dmixer の入力数(すなわち、バス数)は設定可能なプロパティです。デフォルトでは、3DMixer には 64 のバスがあります。バスはメモリを使用するため、バスカウントはアプリケーションに必要な値よりも高く設定しないようにします。このプロパティの設定は、ミキサーユニットを初期化する前に行う必要があります。

リスト 2: ミキサーバスカウントの設定

 
OSStatus    SetMixerBusCount (UInt32    inBusCount)
{

        UInt32  size        = sizeof(UInt32);
        UInt32  busCount    = inBusCount;
    
        return (AudioUnitSetProperty (    mMixerUnit,
                            kAudioUnitProperty_BusCount,
                            kAudioUnitScope_Input,
                            0,
                            &busCount,
                            size));
    
}

先頭に戻る

内部リバーブの使い方

3Dmixer には、リバーブ機能が組み込まれています。オンにすると、(後述のように)入力バスごとにリバーブが適用されます。リバーブはデフォルトではオフになっており、グラフを初期化する前に、AudioUnitSetProperty() メソッドに kAudioUnitProperty_UsesInternalReverb プロパティを指定してオンにすることができます。

リスト 3: 内部リバーブの有効化

 
    UInt32        reverbSetting    = 1 // リバーブをオンにする
    result = AudioUnitSetProperty(mMixerUnit,
                          kAudioUnitProperty_UsesInternalReverb,
                          kAudioUnitScope_Global,
                          0,
                          &reverbSetting,
                          sizeof(reverbSetting));

3DMixer のリバーブをオンにしたら、k3DMixerRenderingFlags_DistanceDiffusion フラグを設定することで、バスごとにリバーブを有効にすることができます。このフラグを設定するには、AudioUnitSetProperty() メソッドに kAudioUnitProperty_3DMixerRenderingFlags プロパティを指定します。このプロパティはいつでも設定できます。

リスト 4: バスのリバーブをオンにする

 
    UInt32    render_flags_3d;
    UInt32    outSize = sizeof(render_flags_3d);

    // このバスの現在のレンダーフラグを取得する
    result = AudioUnitGetProperty (mMixerUnit,
            kAudioUnitProperty_3DMixerRenderingFlags,
            kAudioUnitScope_Input,
            busIndex,
            &render_flags_3d,
            &outSize);

    // このレンダーフラグをオンにしてからバスを設定する
    render_flags_3d |= k3DMixerRenderingFlags_DistanceDiffusion;
    result = AudioUnitSetProperty(    mMixerUnit,
             kAudioUnitProperty_3DMixerRenderingFlags,
             kAudioUnitScope_Input, busIndex,
             &render_flags_3d,
             sizeof(render_flags_3d));

先頭に戻る

スピーカー設定

3DMixer v2.0 はオーディオをステレオ、4 チャネル、5.0 チャネルレイアウトにレンダリングすることが可能です。3DMixer v2.0 は、出力ストリームフォーマットが設定されたときに、チャネルレイアウトを適切に設定しますが、チャネルレイアウトは明示的に設定することをお勧めします。そうすれば、同じチャネル数(すなわち、5.1 と 6.0)を使用するマルチチャネルレイアウトをサポートするミキサーが将来リリースされても、コードを変更する必要がなくなります。チャネルレイアウトを明示的に設定する際には、ストリームフォーマットのチャネルカウントに一致するレイアウトを必ず選んでください。さもなければエラーが返されます(たとえば、5 つのチャネルのあるストリームフォーマットに対して、4 チャネル用のチャネルレイアウトを設定するとエラーが返されます)。複数チャネルのレイアウトにレンダリングできるミキサーの機能をフル活用するためには、カレントデバイスの出力チャネルレイアウトを問い合わせて、Audio MIDI 設定アプリケーションでスピーカー設定にユーザが何を設定しているかを調べる必要があります(次の例を参照)。

次のコードは、グラフの出力ユニットに問い合わせを行うことで、ミキサーのストリームフォーマット(出力範囲)を設定するときに使用する適切なチャネルカウントを調べます。

注意: Audio MIDI 設定で、ユーザがマルチチャネルハードウェア装置用のスピーカー設定(チャネルレイアウト)を設定している可能性があることを頭に入れておいてください。ただし、すべてのハードウェアチャネルにスピーカーが接続されていない可能性もあります(つまり、8 チャネルの装置に 2 つのスピーカーが接続されている場合など)。この場合は、スピーカーが接続されていないデバイスチャネルにオーディオデータがレンダリングされないように、ユーザにステレオレンダリングを指定させ、アプリケーションをステレオに固定するのが適切かもしれません。

リスト 5: レンダリング対象の正しいチャネル数の調査

 
UInt32 GetDesiredRenderChannelCount ()
{
    OSStatus result = noErr;

    // 出力 AU から HAL デバイス ID を取得する
    AudioDeviceID    deviceID;
    UInt32    returnValue = 2;    // デフォルトの場合は、ステレオを返す

    UInt32 outSize =  sizeof(deviceID);

    // カレントデバイスを取得する
    AudioUnitGetProperty(mOutputUnit,
                        kAudioOutputUnitProperty_CurrentDevice,
                        kAudioUnitScope_Output,
                        1,
                        &deviceID,
                        &outSize);

    //ユーザのスピーカー設定を取得する
    result = AudioDeviceGetPropertyInfo(deviceID,
                        0,
                        false,
                        kAudioDevicePropertyPreferredChannelLayout,
                        &outSize,
                        NULL);
    
    if (result != noErr)
        return (returnValue);   // デフォルト(ステレオ)を返す

    AudioChannelLayout    *layout = NULL;
    layout = (AudioChannelLayout *) calloc(1, outSize);
    if (layout != NULL)
    {
        result = AudioDeviceGetProperty(deviceID,
                       0,
                       false,
                       kAudioDevicePropertyPreferredChannelLayout,
                       &outSize,
                       layout);
        if (layout->mChannelLayoutTag
                       == kAudioChannelLayoutTag_UseChannelDescriptions)
        {
        // チャネルレイアウトタグが返されない場合は、
                //チャネル記述をウォークスルーし、
                // スピーカーの接続されているチャネルをカウントする
        if (layout->mNumberChannelDescriptions == 2)
        {
                returnValue = 2;    // ステレオのチャネル情報がない
        }
        else
        {
            returnValue = 0;
            for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; i++)
            {
                if (layout->mChannelDescriptions[i].mChannelLabel !=
                                             kAudioChannelLabel_Unknown)
                    returnValue++;
                }
            }
        }
        else
        {
            switch (layout->mChannelLayoutTag)
            {
                case kAudioChannelLayoutTag_AudioUnit_5_0:
                case kAudioChannelLayoutTag_AudioUnit_5_1:
                case kAudioChannelLayoutTag_AudioUnit_6:
                    returnValue = 5;
                    break;
                case kAudioChannelLayoutTag_AudioUnit_4:
                    returnValue = 4;
                default:
                    returnValue = 2;
            }
        }
    
        free(layout);
    }
  return returnValue;
}

重要: ミキサーの出力ストリームフォーマットは、出力ユニットに接続する前に設定する必要があります。ミキサーを出力ユニットに接続した後は、出力ユニットの入力範囲レイアウトに一致するように、チャネルレイアウトを明示的に設定しなければなりません。

リスト 6: AUGraph のチャネルレイアウトを設定する

 
void ConfigureGraphForChannelLayout()
{
    OSStatus    result = noErr;

    // ミキサーの出力ストリームフォーマットに
        // 設定するチャネルレイアウトを取得する
    mCurrentMixerChannelCount = GetDesiredRenderChannelCount();

    // ストリームフォーマットを設定する
    CAStreamBasicDescription format; //CoreAudio SDK クラス
    UInt32 outSize = sizeof(format);
    result = AudioUnitGetProperty(mOutputUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               0,
                               &format,
                               &outSize);
      
        // インターリーブされていない
    format.SetCanonical (mCurrentMixerChannelCount, false);
    format.mSampleRate = mMixerOutputRate;
    outSize = sizeof(format);
    result = AudioUnitSetProperty (mOutputUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Input,
                               0,
                               &format,
                               outSize);

    result = AudioUnitSetProperty (mMixerUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               0,
                               &format,
                               outSize);

    return;
}

先頭に戻る

立体空間でのサウンドの定位

バスの距離、仰角、および方位角を設定すると、リスナーは立体空間の特定のポイントから音が聞こえます。

オーディオソースのピッチと増幅率は、3DMixer 内でバスごとに変更することができます。ピッチを変えるには、k3DMixerParam_PlaybackRate パラメータの値を変更します。増幅率を変えるには、k3DMixerParam_Gain パラメータの値を変更します(「ボリュームの設定」の例を参照)。

注意: ここでいう増幅率とは、実オーディオデータのボリュームをスケーリングするためのものです。オーディオの空間的な減衰はすべて、ミキサーバスで距離パラメータを設定することによって実現します。

表 1: 3D パラメータ(位置)

指示単位範囲
方位角-180 〜 180
仰角-90 〜 90
距離メートル0 〜 10000

表 2: 3D パラメータ(ボリュームとピッチ)

指示単位範囲
増幅率dB-120 〜 20
再生速度(ピッチ)レート0.5 〜 4.0

リスト 7: 距離と方位角の設定

 
void    SetObjectCoordinates(UInt32     inMixerInputBus, Float32,
inAzimuth, Float32 inDistance)
{
    AudioUnitSetParameter(mMixerUnit,
                                            k3DMixerParam_Azimuth,
                                            kAudioUnitScope_Input,
                                            inMixerInputBus,
                                            inAzimuth,
                                            0);

    AudioUnitSetParameter(mMixerUnit,
                                            k3DMixerParam_Distance,
                                            kAudioUnitScope_Input,
                                            inMixerInputBus,
                                            inDistance,
                                            0);
}

3DMixer v2.0 からは、指定した ReferenceDistance、MaximumDistance、および Attenuation 設定にバスボリュームを固定するのに必要なすべての作業をミキサーにさせることができます。この機能により、アプリケーションは立体空間のオブジェクトが実際にリスナーからどの程度離れられるかを指定することができます。以下の方法は、AudioUnitSetProperty() メソッドと kAudioUnitProperty_3DMixerDistanceParams パラメータを使ってミキサーバスの DistanceParams を適切に設定および取得する方法を示しています。

リスト 8: AudioUnitProperties.h に定義されているミキサーの距離パラメータ構造体

  

typedef struct MixerDistanceParams {
    Float32            mReferenceDistance;
    Float32            mMaxDistance;
    Float32            mMaxAttenuation;    // デシベル単位
} MixerDistanceParams;
Distance Parameters Graph

図 2: 距離パラメータのグラフ

リスト 9: バスの距離パラメータの設定

 
void    SetDistanceParamsForBus (UInt32     inMixerInputBus)
{
         MixerDistanceParams    distanceParams;

    // オブジェクトがリスナーに近づける
    // 最短距離の希望値を取得する(メートル単位の浮動小数点数値)
    // ミキサーは、0.0 とこの基準距離の間にある
    // すべての距離座標に対して、0db の減衰(減衰なし)で
    // オーディオを バス上で再生します。
    // この値は最大距離の設定値未満でなければなりません。
    distanceParams.mReferenceDistance = GetMyMinimumDistance();
    
    // オブジェクトがリスナーから遠ざかることのできる
    // 最大距離の希望値を取得する(メートル単位の浮動少数値)
    // ミキサーは、この最大距離以上の
    // すべての距離座標に対して、
    // バス上のオーディオの減衰を止めます。
    // この値は基準距離の設定より大きくなければなりません。
    distanceParams.mMaxDistance = GetMyMaximumDistance();
    
    // オブジェクトの座標が最大距離
    // (dB 単位の正の浮動小数点数値)であるときの
    // オブジェクトの減衰(db 単位)の希望値を取得します。
    // 距離座標が最大距離設定を超えている場合、
    // ミキサーはこの db 設定以上には
    // オーディオを減衰しません。

    distanceParams.mMaxAttenuation = GetMyMinimumAttenuation();

    OSStatus result = AudioUnitSetProperty(mMixerUnit,
                                kAudioUnitProperty_3DMixerDistanceParams,
                                kAudioUnitScope_Input,
                                inMixerInputBus,
                                &distanceParams,
                                sizeof(distanceParams));


}

先頭に戻る

空間化レンダリングのアルゴリズム

空間化設定は、バス(ミキサー入力)ごとに、AudioUnitSetProperty() メソッドと kAudioUnitProperty_SpatializationAlgorithm 定数を使って設定します。使用されて空間化レンダリングのタイプは、ソースオーディオチャネル(モノラル/ステレオ)、出力ハードウェアチャネル(ステレオ、マルチチャネル)、および CPU 性能などの要素によって決まります。バス空間化アルゴリズムを設定すると、バスレンダリングフラグ(kAudioUnitProperty_3DMixerRenderingFlags)の一部が変更される可能性があるため、空間化アルゴリズムを設定した後で必要なレンダリングフラグを再設定することをお勧めします。

表 3: ステレオ出力に適した空間化アルゴリズム(AudioUnitProperies.h で定義)

アルゴリズム説明出力
kSpatializationAlgorithm_StereoPassThroughStereoPassThrough は、ステレオソースデータを定位する必要がない場合に使用します。このアルゴリズムを設定すると、ミキサーに対してステレオ入力を受け取り、定位しないでチャネル 1 と 2(レンダリングがマルチチャネル向けの場合は、フロントのL/R)に直接渡すように指示します。ステレオ、マルチチャネル
kSpatializationAlgorithm_EqualPowerPanningEqualPowerPanning はただ、ミキサーバスのデータをステレオフィールドにパンするだけです。このアルゴリズムは、ミキシングボードのチャネルストリップにあるパンつまみに似ています。ミキサーがマルチチャネルハードウェアにレンダリングするときにこのアルゴリズムを使うと、オーディオデータはチャネル 1 と 2 (フロントの L/R)にのみレンダリングされます。ステレオ
kSpatializationAlgorithm_HRTFHRTF (Head Related Transfer Function) は、フィルタリングを利用してヘッドフォンやステレオスピーカーで立体空間をエミュレートする高品質のアルゴリズムです。マルチチャネルハードウェアにレンダリングするときにオンにすると、HRTF は入力データをチャネル 1 と 2 (フロントの L/R)にのみレンダリングします。HRTF は CPU に負担のかかるアルゴリズムです。ステレオ
kSpatializationAlgorithm_SphericalHeadHRTF と同様に、SpericalHead アルゴリズムはヘッドフォンやステレオスピーカーで立体空間をエミュレートするのが目的です。簡易化したアルゴリズムを使用しているため、SpericalHead は HRTF と比べると品質のレンダリング結果が劣りますが、CPU の負担がわずかに軽くなります。ステレオ
kSpatializationAlgorithm_SoundField(サラウンドサウンド)SoundField はマルチチャネルハードウェアにレンダリングするのが目的です。ミキサーは SoundField でレンダリングされたデータを受け取り、音源の位置に向かって重みづけをして、すべての出力チャネルに分配します。これは、空間の特定位置から発し、しかもリスナーのいる空間全体で聞こえるサラウンドサウンドには非常に効果的です。マルチチャネル

リスト 10: 3DMixer への空間化アルゴリズムの設定

  
SetSpatializationAlgorithm( UInt32 BusNumber)
{
          UInt32 spatialSetting = GetMySpatializationSetting();

          result = AudioUnitSetProperty(mMixerUnit,
                             kAudioUnitProperty_SpatializationAlgorithm,
                             kAudioUnitScope_Input,
                             BusNumber,
                             &spatialSetting,
                             sizeof(spatialSetting));
}

先頭に戻る

ボリュームの設定

ボリュームは、3DMixer の入力範囲にある各バスに明示的に設定することができ、サウンドをミックスする前に増幅します。各ミキサーバス(入力範囲)のボリュームを設定するには、k3DMixerParam_Gain 定数と AudioUnitSetParameter() メソッドを使用します。パラメータは dB を示す浮動小数点数です(以下を参照)。

リスト 11: 入力時のボリューム設定

 
// busGain は 0.0 〜 1.0(フルボリューム)の範囲
SetInputBusGain(UInt32 mCurrentPlayBus, Float32 busGain)
{
   Float32    db = 20.0 * log10(busGain);     // db に変換
   if (db < -120.0)
      db = -120.0;  // 最低可聴レベルを -120db に固定

   AudioUnitSetParameter(mMixerUnit,
                                       k3DMixerParam_Gain,
                                       kAudioUnitScope_Input,
                                       mCurrentPlayBus,
                                       db,
                                       0);
}

先頭に戻る

バスストリームフォーマットと FormatConverterAU

FormatConverterAU がミキサーバスにデータを供給する場合、ミキサーの入力範囲にあるストリームフォーマットは、ノードが接続されたときに自動的に設定されます。しかし、バスのレンダリングプロシージャでデータをミキサーに直接供給する場合は、データを「プル」する前に、ミキサーのバスの入力範囲にあるストリームフォーマットを適切に設定する必要があります。

注意: ミキサーのバスのストリームフォーマットを設定する場合は、ミキサーはステレオデータをインターリーブされていないものとして受け取ることを想定しています。

先頭に戻る

AUGraph の接続、初期化、開始

設定が完了すれば、3DMixer をデフォルトの出力オーディオユニットに接続することができます。すべての接続が行われ、ノードが正しく設定されたら、AUGraph を初期化する必要があります。グラフの用意ができたら、3Dmixer は使える状態にあります。AUGraphStart を呼び出すと、オーディオデータの処理が開始されます。

リスト 12: AUGraph の接続、初期化、開始

  
    
       AUGraphConnectNodeInput (mAUGraph, mMixerNode, 0, mOutputNode, 0);
 
       AUGraphInitialize (mAUGraph);
       AUGraphStart(mAUGraph);

先頭に戻る

AUGraph の破棄

AUGraphStop メソッドは、グラフのレンダリングをすべて停止します。DisposeAUGraph はグラフの割り当てを解除します。

リスト 13: グラフの停止と破棄

        AUGraphStop (mAUGraph);

        DisposeAUGraph (mAUGraph);
        mAUGraph = 0;
    

先頭に戻る

まとめ

CoreAudio の 3DMixer は大変役に立つオーディオツールです。複数のソースのオーディオを処理し、サウンドを立体空間に定位するミキサーの機能は、ゲームには不可欠なものであり、他の無数のアプリケーションでも驚くべき効果をもたらす可能性があります。

先頭に戻る

参考資料と注意

Core Audio Preliminary doc

先頭に戻る

ドキュメントの改訂履歴

日付メモ
2004-06-14標準ライブラリの場所を更新
2004-05-26最初のバージョン

掲載日: 2004-06-14