View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Vidéos

Ouvrir le menu Fermer le menu
  • Collections
  • Toutes les vidéos
  • À propos

Plus de vidéos

  • À propos
  • Code
  • Discover geometry-aware audio with the Physical Audio Spatialization Engine (PHASE)

    Explore how geometry-aware audio can help you build complex, interactive, and immersive audio scenes for your apps and games. Meet PHASE, Apple's spatial audio API, and learn how the Physical Audio Spatialization Engine (PHASE) keeps the sound aligned with your experience at all times — helping you create spatial soundscapes and scenes during the development process, rather than waiting until post production. We'll take you through an overview of the API and its classes, including Sources, Listeners, Acoustic Geometry, and Materials, and introduce the concept of Spatial Modeling. We'll also show you how to quickly combine PHASE's basic building blocks to start building an integrated audio experience for your app or game.

    Ressources

    • PHASE
      • Vidéo HD
      • Vidéo SD

    Vidéos connexes

    WWDC23

    • Bring your game to Mac, Part 1: Make a game plan

    WWDC22

    • Plug-in and play: Add Apple frameworks to your Unity game projects
  • Rechercher dans cette vidéo…
    • 18:31 - Create an Engine and Register a Sound Asset

      // Create an Engine in Automatic Update Mode.
      let engine = PHASEEngine(updateMode: .automatic)
      
      // Retrieve the URL to an Audio File stored in our Application Bundle.
      let audioFileUrl = Bundle.main.url(forResource: "DrumLoop_24_48_Mono", withExtension: "wav")!
      
      // Register the Audio File at the URL.
      // Name it "drums", load it into resident memory and apply dynamic normalization to prepare it for playback.
      let soundAsset = try engine.assetRegistry.registerSoundAsset(url: audioFileUrl,
                                                                   identifier: "drums",
                                                                   assetType: .resident,
                                                                   channelLayout: nil,
                                                                   normalizationMode: .dynamic)
    • 20:47 - Register a Sound Event Asset

      // Create a Channel Layout from a Mono Layout Tag.
      let channelLayout = AVAudioChannelLayout(layoutTag: kAudioChannelLayoutTag_Mono)!
           
      // Create a Channel Mixer from the Channel Layout.
      let channelMixerDefinition = PHASEChannelMixerDefinition(channelLayout: channelLayout)
      
      // Create a Sampler Node from "drums" and hook it into the downstream Channel Mixer.
      let samplerNodeDefinition = PHASESamplerNodeDefinition(soundAssetIdentifier: "drums",
                                                             mixerDefinition: channelMixerDefinition)
      
      // Set the Sampler Node's Playback Mode to Looping.
      samplerNodeDefinition.playbackMode = .looping;
      
      // Set the Sampler Node's Calibration Mode to Relative SPL and Level to 0 dB.
      samplerNodeDefinition.setCalibrationMode(.relativeSpl, level: 0)
      
      // Register a Sound Event Asset with the Engine named "drumEvent".
      let soundEventAsset = try engine.assetRegistry.registerSoundEventAsset(rootNode:samplerNodeDefinition,
                                                   identifier: "drumEvent")
    • 22:21 - Start a Sound Event

      // Create a Sound Event from the Sound Event Asset "drumEvent".
      let soundEvent = try PHASESoundEvent(engine: engine, assetIdentifier: "drumEvent")
      
      // Start the Engine.
      // This will internally start the Audio IO Thread.
      try engine.start()
      
      // Start the Sound Event.
      try soundEvent.start()
    • 23:05 - Cleanup

      // Stop and invalidate the Sound Event.
      soundEvent.stopAndInvalidate()
      
      // Stop the Engine.
      // This will internally stop the Audio IO Thread.
      engine.stop()
      
      // Unregister the Sound Event Asset.
      engine.assetRegistry.unregisterAsset(identifier: "drumEvent", completionHandler:nil)
      
      // Unregister the Audio File.
      engine.assetRegistry.unregisterAsset(identifier: "drums", completionHandler:nil)
      
      // Destroy the Engine.
      engine = nil
    • 25:14 - Create a Sound Event Asset

      // Create a Spatial Pipeline.
      let spatialPipelineOptions: PHASESpatialPipeline.Options = [.directPathTransmission, .lateReverb]
      let spatialPipeline = PHASESpatialPipeline(options: spatialPipelineOptions)!
      spatialPipeline.entries[PHASESpatialCategory.lateReverb]!.sendLevel = 0.1;
      engine.defaultReverbPreset = .mediumRoom
      
      // Create a Spatial Mixer with the Spatial Pipeline.
      let spatialMixerDefinition = PHASESpatialMixerDefinition(spatialPipeline: spatialPipeline)
      
      // Set the Spatial Mixer's Distance Model.
      let distanceModelParameters = PHASEGeometricSpreadingDistanceModelParameters()
      distanceModelParameters.fadeOutParameters = PHASEDistanceModelFadeOutParameters(cullDistance: 10.0)
      distanceModelParameters.rolloffFactor = 0.25
      spatialMixerDefinition.distanceModelParameters = distanceModelParameters
      
      // Create a Sampler Node from "drums" and hook it into the downstream Spatial Mixer.
      let samplerNodeDefinition = PHASESamplerNodeDefinition(soundAssetIdentifier: "drums", mixerDefinition:spatialMixerDefinition)
      
      // Set the Sampler Node's Playback Mode to Looping.
      samplerNodeDefinition.playbackMode = .looping
      
      // Set the Sampler Node's Calibration Mode to Relative SPL and Level to 12 dB.
      samplerNodeDefinition.setCalibrationMode(.relativeSpl, level: 12)
      
      // Set the Sampler Node's Cull Option to Sleep.
      samplerNodeDefinition.cullOption = .sleepWakeAtRealtimeOffset;
      
      // Register a Sound Event Asset with the Engine named "drumEvent".
      let soundEventAsset = try engine.assetRegistry.registerSoundEventAsset(rootNode: samplerNodeDefinition, identifier: "drumEvent")
    • 27:05 - Set Up a Listener

      // Create a Listener.
      let listener = PHASEListener(engine: engine)
      
      // Set the Listener's transform to the origin with no rotation.
      listener.transform = matrix_identity_float4x4;
      
      // Attach the Listener to the Engine's Scene Graph via its Root Object.
      // This actives the Listener within the simulation.
      try engine.rootObject.addChild(listener)
    • 27:46 - Set Up a Volumetric Source

      // Create an Icosahedron Mesh.
      let mesh = MDLMesh.newIcosahedron(withRadius: 0.0142, inwardNormals: false, allocator:nil)
      
      // Create a Shape from the Icosahedron Mesh.
      let shape = PHASEShape(engine: engine, mesh: mesh)
      
      // Create a Volumetric Source from the Shape.
      let source = PHASESource(engine: engine, shapes: [shape])
      
      // Translate the Source 2 meters in front of the Listener and rotated back toward the Listener.
      var sourceTransform: simd_float4x4
      sourceTransform.columns.0 = simd_make_float4(-1.0, 0.0, 0.0, 0.0)
      sourceTransform.columns.1 = simd_make_float4(0.0, 1.0, 0.0, 0.0)
      sourceTransform.columns.2 = simd_make_float4(0.0, 0.0, -1.0, 0.0)
      sourceTransform.columns.3 = simd_make_float4(0.0, 0.0, 2.0, 1.0)
      source.transform = sourceTransform;
      
      // Attach the Source to the Engine's Scene Graph.
      // This actives the Listener within the simulation.
      try engine.rootObject.addChild(source)
    • 29:15 - Set Up an Occluder

      // Create a Box Mesh.
      let boxMesh = MDLMesh.newBox(withDimensions: simd_make_float3(0.6096, 0.3048, 0.1016),
                                   segments: simd_uint3(repeating: 6),
                                   geometryType: .triangles,
                                   inwardNormals: false,
                                   allocator: nil)
      
      // Create a Shape from the Box Mesh.
      let boxShape = PHASEShape(engine: engine, mesh:boxMesh)
      
      // Create a Material.
      // In this case, we'll make it 'Cardboard'.
      let material = PHASEMaterial(engine: engine, preset: .cardboard)
      
      // Set the Material on the Shape.
      boxShape.elements[0].material = material
      
      // Create an Occluder from the Shape.
      let occluder = PHASEOccluder(engine: engine, shapes: [boxShape])
          
      // Translate the Occluder 1 meter in front of the Listener and rotated back toward the Listener.
      // This puts the Occluder half way between the Source and Listener.
      var occluderTransform: simd_float4x4
      occluderTransform.columns.0 = simd_make_float4(-1.0, 0.0, 0.0, 0.0)
      occluderTransform.columns.1 = simd_make_float4(0.0, 1.0, 0.0, 0.0)
      occluderTransform.columns.2 = simd_make_float4(0.0, 0.0, -1.0, 0.0)
      occluderTransform.columns.3 = simd_make_float4(0.0, 0.0, 1.0, 1.0)
      occluder.transform = occluderTransform
      
      // Attach the Occluder to the Engine's Scene Graph.
      // This actives the Occluder within the simulation.
      try engine.rootObject.addChild(occluder)
    • 30:33 - Start a Spatial Sound Event

      // Associate the Source and Listener with the Spatial Mixer in the Sound Event.
      let mixerParameters = PHASEMixerParameters()
      mixerParameters.addSpatialMixerParameters(identifier: spatialMixerDefinition.identifier, source: source, listener: listener)
      
      // Create a Sound Event from the built Sound Event Asset "drumEvent".
      let soundEvent = try PHASESoundEvent(engine: engine, assetIdentifier: "drumEvent", mixerParameters: mixerParameters)
    • 31:28 - Example 1: Footstep on creaky wood

      // Create a Sampler Node from "footstep_wood_clip_1" and hook it into a Channel Mixer.
      let footstep_wood_sampler_1 = PHASESamplerNodeDefinition(soundAssetIdentifier: "footstep_wood_clip_1", mixerDefinition: channelMixerDefinition)
    • 31:54 - Example 2: Random footsteps on creaky wood

      // Create a Sampler Node from "footstep_wood_clip_1" and hook it into a Channel Mixer.
      let footstep_wood_sampler_1 = PHASESamplerNodeDefinition(soundAssetIdentifier: "footstep_wood_clip_1", mixerDefinition: channelMixerDefinition)
      
      // Create a Sampler Node from "footstep_wood_clip_2" and hook it into a Channel Mixer.
      let footstep_wood_sampler_2 = PHASESamplerNodeDefinition(soundAssetIdentifier: "footstep_wood_clip_2", mixerDefinition: channelMixerDefinition)
      
      // Create a Random Node.
      // Add 'Footstep on Creaky Wood' Sampler Nodes as children of the Random Node.
      // Note that higher weights increase the likelihood of that child being chosen.
      let footstep_wood_random = PHASERandomNodeDefinition()
      footstep_wood_random.addSubtree(footstep_wood_sampler_1, weight: 2)
      footstep_wood_random.addSubtree(footstep_wood_sampler_2, weight: 1)
    • 32:47 - Example 3: Random footsteps on creaky wood or soft gravel

      // Create a Sampler Node from "footstep_gravel_clip_1" and hook it into a Channel Mixer.
      let footstep_gravel_sampler_1 = PHASESamplerNodeDefinition(soundAssetIdentifier: "footstep_gravel_clip_1", mixerDefinition: channelMixerDefinition)
      
      // Create a Sampler Node from "footstep_gravel_clip_2" and hook it into a Channel Mixer.
      let footstep_gravel_sampler_2 = PHASESamplerNodeDefinition(soundAssetIdentifier: "footstep_gravel_clip_2", mixerDefinition: channelMixerDefinition)
      
      // Create a Random Node.
      // Add 'Footstep on Soft Gravel' Sampler Nodes as children of the Random Node.
      // Note that higher weights increase the likelihood of that child being chosen.
      let footstep_gravel_random = PHASERandomNodeDefinition()
      footstep_gravel_random.addSubtree(footstep_gravel_sampler_1, weight: 2)
      footstep_gravel_random.addSubtree(footstep_gravel_sampler_2, weight: 1)
      
      // Create a Terrain String MetaParameter.
      // Set the default value to "creaky_wood".
      let terrain = PHASEStringMetaParameterDefinition(value: "creaky_wood")
      
      // Create a Terrain Switch Node.
      // Add 'Random Footstep on Creaky Wood' and 'Random Footstep on Soft Gravel' as Children.
      let terrain_switch = PHASESwitchNodeDefinition(switchMetaParameterDefinition: terrain)
      terrain_switch.addSubtree(footstep_wood_random, switchValue: "creaky_wood")
      terrain_switch.addSubtree(footstep_gravel_random, switchValue: "soft_gravel")
    • 34:08 - Example 4: Random footsteps on changing terrain with a variably wet surface

      // Create a Sampler Node from "splash_clip_1" and hook it into a Channel Mixer.
      let splash_sampler_1 = PHASESamplerNodeDefinition(soundAssetIdentifier: "splash_clip_1", mixerDefinition: channelMixerDefinition)
          
      // Create a Sampler Node from "splash_clip_2" and hook it into a Channel Mixer.
      let splash_sampler_2 = PHASESamplerNodeDefinition(soundAssetIdentifier: "splash_clip_2", mixerDefinition: channelMixerDefinition)
      
      // Create a Random Node.
      // Add 'Splash' Sampler Nodes as children of the Random Node.
      // Note that higher weights increase the likelihood of that child being chosen.
      let splash_random = PHASERandomNodeDefinition()
      splash_random.addSubtree(splash_sampler_1, weight: 9)
      splash_random.addSubtree(splash_sampler_2, weight: 7)
      
      // Create a Wetness Number MetaParameter.
      // The range is [0, 1], from dry to wet. The default value is 0.5.
      let wetness = PHASENumberMetaParameterDefinition(value: 0.5, minimum: 0, maximum: 1)
          
      // Create a 'Wetness' Blend Node that blends between dry and wet terrain.
      // Add 'Terrain' Switch Node and 'Splash' Random Node as children.
      // As you increase the wetness, the mix between the dry footsteps and splashes will change.
      let wetness_blend = PHASEBlendNodeDefinition(blendMetaParameterDefinition: wetness)
      wetness_blend.addRangeForInputValues(belowValue: 1, fullGainAtValue: 0, fadeCurveType: .linear, subtree: terrain_switch)
      wetness_blend.addRangeForInputValues(aboveValue: 0, fullGainAtValue: 1, fadeCurveType: .linear, subTree: splash_random)
    • 35:53 - Example 5: Random footsteps on changing terrain with a variably wet surface and noisy Gore-Tex Jacket

      // Create a Sampler Node from "gortex_clip_1" and hook it into a Channel Mixer.
      let noisy_clothing_sampler_1 = PHASESamplerNodeDefinition(soundAssetIdentifier: "gortex_clip_1", mixerDefinition: channelMixerDefinition)
      
      // Create a Sampler Node from "gortex_clip_2" and hook it into a Channel Mixer.
      let noisy_clothing_sampler_2 = PHASESamplerNodeDefinition(soundAssetIdentifier: "gortex_clip_2", mixerDefinition: channelMixerDefinition)
      
      // Create a Random Node.
      // Add 'Noisy Clothing' Sampler Nodes as children of the Random Node.
      // Note that higher weights increase the likelihood of that child being chosen.
      let noisy_clothing_random = PHASERandomNodeDefinition()
      noisy_clothing_random.addSubtree(noisy_clothing_sampler_1, weight: 3)
      noisy_clothing_random.addSubtree(noisy_clothing_sampler_2, weight: 5)
      
      // Create a Container Node.
      // Add 'Wetness' Blend Node and 'Noisy Clothing' Random Node as children.
      let actor_container = PHASEContainerNodeDefinition()
      actor_container.addSubtree(wetness_blend)
      actor_container.addSubtree(noisy_clothing_random)

Developer Footer

  • Vidéos
  • WWDC21
  • Discover geometry-aware audio with the Physical Audio Spatialization Engine (PHASE)
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines