Sample CodevisionOSReviewed 2026-07-21View on Apple Developer

Mixing spatial music

At a glance

Item Summary
Purpose Preview ray-traced reverb by adjusting a spatialized multitrack audio mix in an immersive scene.
App architecture MixingSpatialMusicApp owns AppModel; the immersive scene creates spatial emitters while mixer/settings views mutate source levels and visual models reflect the same audio-scene state.
Main patterns SwiftUI scene composition, UI–RealityKit bridge, Observable state owner, Async update consumer, Scene-backed audio mixer
Project style Code-rich sample with 21 scanned Swift file(s) and 1628 implementation line(s).

Project structure

Source bundle/
└── MixingSpatialMusic/
    ├── AppModel.swift  # AppModel, ImmersiveSpaceState
    ├── Views/
    │   ├── ImmersiveView.swift  # ImmersiveView
    │   ├── AudioMixer/
    │   │   └── MixerView.swift  # MixerView
    │   └── SettingsView.swift  # SettingsView
    ├── MixingSpatialMusicApp.swift  # MixingSpatialMusicApp
    ├── ECS/
    │   └── ViewpointComponent.swift  # ViewpointComponent
    └── Model/
        └── AudioStem.swift  # AudioStem, VisualModel

Structure observations

  • The runtime boundary is WindowGroup + ImmersiveSpace + SwiftUI/UIKit host; the tree is pruned to lifecycle, state, framework, rendering, and ECS files.
  • The source is Swift; role-named types and feature folders separate the major responsibilities.

Overall architecture

Reference code

MixingSpatialMusic/MixingSpatialMusicApp.swift:11 — executable or app-lifecycle anchor.

struct MixingSpatialMusicApp: App {
    // ...
}

The diagram is a responsibility flow, not a claim that every adjacent node directly calls the next. It separates lifecycle, presentation, stable state, framework/session work, and the RealityKit entity graph.

Ownership and state

Ownership evidence

MixingSpatialMusic/MixingSpatialMusicApp.swift:13 — representative stored state or nearest verified lifecycle anchor.

@main
struct MixingSpatialMusicApp: App {
    // ...
    @State private var appModel = AppModel()
    // ...
}
Owner Object or state Relationship Mutation authority
MixingSpatialMusicApp AppModel as appModel creates and retains The declaring type controls writes
AppModel Entity as root creates and retains The owning type coordinates writes
AppModel Entity as audioSourcesRoot creates and retains The owning type coordinates writes
AppModel AudioPlaybackGroupController as playbackController stores and coordinates The owning type coordinates writes

Ownership is intentionally narrow: environment, bindings, observed objects, weak links, and delegate callbacks do not prove lifetime ownership. Initialized stored services and wrapper-managed state do; entities added inside a RealityKit content closure belong to that entity graph.

Class and protocol design

Type Responsibility Depends on or conforms to
MixingSpatialMusicApp (MixingSpatialMusic/MixingSpatialMusicApp.swift:11) Declares app lifecycle and top-level dependency lifetime. App
ImmersiveView (MixingSpatialMusic/Views/ImmersiveView.swift:11) Presents UI and forwards gestures or lifecycle events. View
AppModel (MixingSpatialMusic/AppModel.swift:14) Owns feature state and domain transitions. Concrete framework collaborators
ViewpointComponent (MixingSpatialMusic/ECS/ViewpointComponent.swift:11) Stores RealityKit entity data. Component
VisualModel (MixingSpatialMusic/Model/AudioStem.swift:28) Owns feature state and domain transitions. Concrete framework collaborators
MixerView (MixingSpatialMusic/Views/AudioMixer/MixerView.swift:13) Presents UI and forwards gestures or lifecycle events. View
SettingsView (MixingSpatialMusic/Views/SettingsView.swift:13) Presents UI and forwards gestures or lifecycle events. View
TrackView (MixingSpatialMusic/Views/AudioMixer/TrackView.swift:12) Presents UI and forwards gestures or lifecycle events. View

The reviewed source defines no local substitution protocol. Its App, View, delegate, renderer, ARKit, and RealityKit conformances are framework-facing contracts, so this document does not label the whole app protocol-oriented.

Access control

Symbol Access Verified effect Likely rationale
private func makeAudioSource(for stem: AudioStem) -> Entity { (MixingSpatialMusic/AppModel.swift:121) private Use stays inside the declaration and same-file extensions permitted by Swift. Inference: Hide lifecycle-sensitive state or an implementation step.
fileprivate static let labeledDecibelValues: [Double] = [-60, -40, -30,... (MixingSpatialMusic/Views/AudioMixer/LabeledFader.swift:113) fileprivate Use is limited to declarations in this source file. Inference: Share with same-file helpers without making the symbol module-wide.

No reviewed Swift access example uses private(set), public, open; declarations without a modifier are internal.

Reference code

MixingSpatialMusic/AppModel.swift:121 — representative visibility boundary.

    private func makeAudioSource(for stem: AudioStem) -> Entity {
        // Construct an audio source entity for the stem.
        let entity: Entity = .makeAudioSource(for: stem)
        audioSourcesRoot.addChild(entity)
        return entity
    }

Logic ownership and placement

Logic Owning type or file Placement rationale
Application/command lifecycle MixingSpatialMusicApp The executable boundary determines app, controller, scene, or command lifetime.
Presentation and user intent ImmersiveView The view/controller forwards input and owns only presentation-local work.
Shared feature state and commands AppModel A stable owner prevents view recomputation or callbacks from duplicating transitions.

Design patterns

Pattern Source evidence Purpose or tradeoff
SwiftUI scene composition MixingSpatialMusic/MixingSpatialMusicApp.swift:11 Keeps windows, volumes, and immersive presentation visible at the app boundary.
UI–RealityKit bridge MixingSpatialMusic/Views/ImmersiveView.swift:16 Builds or hosts the RealityKit entity graph from SwiftUI or a platform view/controller lifecycle.
Observable state owner MixingSpatialMusic/AppModel.swift:14 Keeps shared feature state in a stable owner rather than in transient view values.
Async update consumer MixingSpatialMusic/AppModel.swift:93 Consumes long-lived framework output in a cancellable asynchronous task.
Scene-backed audio mixer MixingSpatialMusic/Views/AudioMixer/MixerView.swift:100 Treats emitters as scene entities while one app model and mixer controls coordinate their playback parameters.

Naming conventions

  • Role suffixes are evidence, not decoration: App: MixingSpatialMusicApp; Model: AppModel, VisualModel; Component: ViewpointComponent; View: ImmersiveView, MixerView, SettingsView, TrackView.
  • ECS names pair data and behavior: components ViewpointComponent; systems none.
  • Protocols: no app-defined protocol in the reviewed source.
  • Commands use verb-led methods: teleportToStartingViewpoint, teleport, loadVisualEnvironment, loadAudioEnvironment, loadAudio, addViewpoints, configureAudioMixGroups, makeAudioSource.
  • Files and folders use primary-type or responsibility names such as Views, Models, Rendering, Components, Systems, Packages, or feature names where those boundaries exist.

Architecture takeaways

  • Treat MixingSpatialMusicApp as the owner of executable or scene lifecycle, not automatically as the owner of every entity created later.
  • Keep view/controller input near presentation, but move sessions, reconstruction, capture, rendering, shared game state, or documents into stable owners when their lifetime exceeds one callback or render pass.
  • Tie asynchronous session/output consumers to an explicit owner so cancellation and teardown follow the same lifecycle.

Source map

Source file Relevant symbols
MixingSpatialMusic/AppModel.swift:14 AppModel, ImmersiveSpaceState
MixingSpatialMusic/Views/ImmersiveView.swift:11 ImmersiveView
MixingSpatialMusic/Views/AudioMixer/MixerView.swift:13 MixerView
MixingSpatialMusic/MixingSpatialMusicApp.swift:11 MixingSpatialMusicApp
MixingSpatialMusic/ECS/ViewpointComponent.swift:11 ViewpointComponent
MixingSpatialMusic/Model/AudioStem.swift:11 AudioStem, VisualModel
MixingSpatialMusic/Views/SettingsView.swift:13 SettingsView