XR アプリに空間オーディオを追加する

Jetpack SceneCore の空間オーディオ機能を使用すると、Android XR アプリ内で没入型の音声エクスペリエンスを作成できます。

空間オーディオは、ユーザーが 3D 環境で音をどのように認識するかをシミュレートします。ユーザーの上や下など、あらゆる方向から音が聞こえるような感覚を作り出すことができます。システムは、3D 空間内の特定の場所にある 1 つ以上の「仮想スピーカー」をシミュレートすることで、この効果を実現します。

Android XR 用に設計または変更されていない既存のアプリでは、Android XR でオーディオが自動的に空間化されます。ユーザーがスペース内を移動すると、アプリの UI がレンダリングされるパネルからアプリの音声がすべて出力されます。たとえば、時計アプリでタイマーが鳴ると、アプリパネルの位置から音が鳴ります。Android XR では、位置情報に基づいて音声が自動的に変化し、臨場感のあるサウンドが実現されます。たとえば、アプリパネルとユーザーとの距離感は、音声の音量に微妙な影響を与え、よりリアルな感覚を演出します。

既存のアプリで空間オーディオをレンダリングする方法について詳しくは、このページのアプリにステレオとサラウンド音声を追加するをご覧ください。

XR 向けにアプリを最適化している場合は、Jetpack SceneCore で高度な空間オーディオのカスタマイズを行うツールを利用できます。3D 環境で音を正確に配置したり、アンビソニック音声を使用してリアルな音場を実現したり、内蔵のサラウンド音声統合を利用したりできます。

Android XR で利用できる空間オーディオの種類

Android XR は、位置情報、ステレオ、サラウンド音声、アンビソニック音声をサポートしています。

位置情報に基づく音声

位置オーディオは、3D 空間内の特定の位置から再生するように配置できます。たとえば、仮想環境の隅で吠えている犬の3D モデルを配置できます。複数のエンティティがそれぞれ異なる位置から音を出すように設定できます。位置情報オーディオをレンダリングするには、ファイルがモノラルまたはステレオである必要があります。

空間オーディオ ステレオとサラウンド音声

すべての Android メディア形式が、位置情報、ステレオ、サラウンド サウンドでサポートされています。

ステレオ音声は 2 つのチャンネルを持つオーディオ形式を指し、サラウンド音声は 2 つを超えるチャンネルを持つオーディオ形式(5.1 サラウンド音声7.1 サラウンド音声の構成など)を指します。各チャンネルの音声データは 1 人のスピーカーに関連付けられます。たとえば、音楽をステレオで再生しているときに、左のスピーカー チャンネルから右とは異なる楽器トラックが鳴る場合があります。

サラウンド サウンドは、映画やテレビ番組でよく使用され、複数のスピーカー チャンネルを使用して臨場感と没入感を高めます。たとえば、会話は通常、中央のスピーカー チャンネルから再生されますが、ヘリコプターの飛行音は、ヘリコプターが 3D 空間を飛んでいるように感じさせるために、さまざまなチャンネルを順番に使用します。

アンビソニック音声

アンビソニック音声(アンビソニック)は、音声のスカイボックスのようなもので、ユーザーに没入感のあるサウンドスケープを提供します。アンビソニックスは、背景の環境音や、リスナーを取り囲む完全球状の音場を再現する必要があるその他のシナリオに使用します。Android XR は、1 次、2 次、3 次アンビソニックスの AmbiX アンビソニック音声形式をサポートしています。Opus.ogg)と PCM/Wave.wav)のファイル形式をおすすめします。

Jetpack SceneCore で空間オーディオを使用する

Jetpack SceneCore で空間オーディオを実装するには、空間機能の確認と、空間オーディオを読み込む API の選択が必要です。

空間機能を確認する

空間オーディオ機能を使用する前に、Session が空間オーディオに対応していることを確認してください。次のセクションのコード スニペットではすべて、空間オーディオの再生を試みる前に機能がチェックされます。

空間オーディオを読み込む

次のいずれかの API を使用して、Jetpack SceneCore で使用する空間オーディオを読み込むことができます。

  • SoundPool: サイズが 1 MB 未満の短い効果音に適しています。事前に読み込まれ、音声を繰り返し使用できます。これは、位置情報に基づく音声の読み込みに適しています。
  • ExoPlayer: 音楽や動画などのステレオ音声やサラウンド音声のコンテンツを読み込むのに適しています。バックグラウンドでのメディア再生も可能です。
  • MediaPlayer: アンビソニック音声を最も簡単に読み込む方法です。
  • AudioTrack: 音声データの読み込み方法を細かく制御できます。音声のバッファを直接書き込むことができます。また、独自の音声ファイルを合成またはデコードする場合にも使用できます。

アプリに位置情報に基づく音声を追加する

位置情報に基づく音源は、PointSourceAttributes と関連する Entity によって定義されます。Entity の位置と向きによって、3D 空間で PointSourceAttribute がレンダリングされる場所が決まります。

位置情報に基づく音声の例

次の例では、効果音のオーディオ ファイルをサウンドプールに読み込み、Entity の位置で再生します。

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val maxVolume = 1F
    val lowPriority = 0
    val infiniteLoop = -1
    val normalSpeed = 1F

    val soundPool = SoundPool.Builder()
        .setAudioAttributes(
            AudioAttributes.Builder()
                .setContentType(CONTENT_TYPE_SONIFICATION)
                .setUsage(USAGE_ASSISTANCE_SONIFICATION)
                .build()
        )
        .build()

    val pointSource = PointSourceAttributes(entity)

    val soundEffect = appContext.assets.openFd("sounds/tiger_16db.mp3")
    val pointSoundId = soundPool.load(soundEffect, lowPriority)

    soundPool.setOnLoadCompleteListener{ soundPool, sampleId, status ->
        //wait for the sound file to be loaded into the soundPool
        if (status == 0){

            SpatialSoundPool.play(
                session = xrSession,
                soundPool = soundPool,
                soundID = pointSoundId,
                attributes = pointSource,
                volume = maxVolume,
                priority = lowPriority,
                loop = infiniteLoop,
                rate = normalSpeed
            )
        }
    }
} else {
    // The session does not have spatial audio capabilities
}

コードに関する主なポイント

  • まず、getSpatialCapabilities() を使用して、空間オーディオ機能が現在利用可能かどうかを確認します。
  • contentType を CONTENT_TYPE_SONIFICATION に、usage を USAGE_ASSISTANCE_SONIFICATION に設定すると、この音声ファイルが効果音として扱われます。
  • 上の例では、コードを簡素にするために、使用直前に音声ファイルをプールに読み込んでいます。理想的には、アプリの読み込み時にすべての効果音を非同期で読み込み、必要に応じてすべての音声ファイルをプールで使用できるようにします。

アプリにステレオ音声とサラウンド音声を追加する

アプリにステレオ音声とサラウンド音声を追加する推奨方法は、Exoplayer を使用する方法です。Exoplayer で空間オーディオを使用する方法について詳しくは、空間オーディオ ガイドをご覧ください。

ステレオとサラウンド音声のスピーカーの配置

サラウンド音声スピーカーの配置では、仮想サラウンド音声スピーカーは、標準の ITU 構成で、中央のスピーカーを基準としてユーザーの周囲に配置されます。

デフォルトでは、センター チャンネル スピーカーはアプリの mainPanelEntity に配置されます。これには、Android XR によって音声が自動的に空間化されるモバイルアプリが含まれます。

ステレオの場合、スピーカーの配置はサラウンド音声と同様ですが、左チャンネルと右チャンネルのみをパネルの左右に配置します。

複数のパネルがあり、音声を出力するパネルを選択する場合や、ステレオ音声またはサラウンド音声を別の Entity を基準にレンダリングする場合は、PointSourceAttributes を使用してセンター チャンネルの位置を定義できます。残りのチャンネルは、前述のように配置されます。このような場合は、MediaPlayer も使用する必要があります。

ユーザーが部屋の中を移動すると、ステレオ音声とサラウンド音声の仮想スピーカーが移動して調整され、スピーカーが常に最適な位置に配置されるようにします。

ステレオ音声またはサラウンド音声をバックグラウンドで再生し続けるように MediaPlayer または ExoPlayer を構成している場合、アプリがバックグラウンドに移行すると、バーチャル スピーカーの位置が変更されます。音を固定するパネルや空間上の他のポイントがないため、空間オーディオはユーザーとともに移動します(つまり、「ヘッドロック」されます)。

サラウンド音声の例

次の例では、MediaPlayer を使用して 5.1 音声ファイルを読み込み、ファイルのセンター チャンネルを Entity に設定します。

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val pointSourceAttributes = PointSourceAttributes(xrSession.mainPanelEntity)

    val mediaPlayer = MediaPlayer()

    val fivePointOneAudio = appContext.assets.openFd("sounds/aac_51.ogg")
    mediaPlayer.reset()
    mediaPlayer.setDataSource(fivePointOneAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setPointSourceAttributes(
        xrSession,
        mediaPlayer,
        pointSourceAttributes)

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()

} else {
    // The session does not have spatial audio capabilities
}

コードに関する主なポイント

アンビソニック音場をアプリに追加する

アンビソニック音場を再生する最も簡単な方法は、MediaPlayer を使用してファイルを読み込むことです。アンビソニック音声はサウンドスケープ全体に適用されるため、位置を指定するために Entity を指定する必要はありません。代わりに、チャネル数を指定する適切なアンビソニック順序で SoundFieldAttributes のインスタンスを作成します。

Ambionics の例

次の例では、MediaPlayer を使用してアンビソニック音場を再生します。

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val soundFieldAttributes =
        SoundFieldAttributes(SpatializerConstants.AMBISONICS_ORDER_FIRST_ORDER)

    val mediaPlayer = MediaPlayer()

    val soundFieldAudio = appContext.assets.openFd("sounds/foa_basketball_16bit.wav")

    mediaPlayer.reset()
    mediaPlayer.setDataSource(soundFieldAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setSoundFieldAttributes(
        xrSession,
        mediaPlayer,
        soundFieldAttributes)

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()

} else {
    // The session does not have spatial audio capabilities
}

コードに関する主なポイント

  • 前のスニペットと同様に、最初のステップは getSpatialCapabilities() を使用して、空間オーディオ機能が現在使用可能かどうかを確認することです。
  • contentType と usage は情報提供のみを目的としています。
  • AMBISONICS_ORDER_FIRST_ORDER は、サウンドフィールド ファイルで 4 つのチャンネルが定義されていることを SceneCore に通知します。