Skip to content

Repository files navigation

Video Music

A modern, evolved clone of the Atari Video Music (C-240, 1977) — a dedicated audio visualizer that generates real-time graphics driven by music. Built as a native tvOS application for Apple TV 4K.

The app plays music from the user's Apple Music library and renders generative visuals on the TV in response to the audio signal. Six distinct visual modes can be cycled via the Siri Remote.


Architecture

Three systems. That's it.

1. Music Playback — MusicKit

  • Uses ApplicationMusicPlayer for independent playback (doesn't affect the system Music app)
  • Requests Apple Music authorization on launch
  • Browse albums, playlists, and search the Apple Music catalog
  • Now Playing overlay with track title, artist, album art — fades out after 4 seconds
  • Standard transport controls via Siri Remote

2. Audio Analysis — AVAudioEngine + FFT

Real-time frequency and amplitude extraction using AVAudioEngine with vDSP (Accelerate framework).

Extracted data every frame:

ParameterRangeDescription
Bass0.0–1.020–250 Hz (kick drums, sub-bass)
Low-Mid0.0–1.0250–500 Hz (warmth, body)
Mid0.0–1.0500–2000 Hz (vocals, snare)
High-Mid0.0–1.02000–6000 Hz (presence, articulation)
High0.0–1.06000–20000 Hz (air, cymbals)
Amplitude0.0–1.0Overall RMS level
Transient0.0–1.0Sharp attack impulse (decays quickly)
Spectral Centroid0.0–1.0Weighted avg frequency (dark↔bright)

All values smoothed with exponential moving average to prevent visual jitter.

Audio Tap Approach

MusicKit's ApplicationMusicPlayer does not expose PCM audio buffers. Apple provides no documented API to tap into MusicKit's audio output stream.

Approach used: Microphone Loopback

  • AVAudioEngine taps the device's input node (microphone)
  • The Apple TV 4K's built-in Siri microphone captures the room audio
  • Music playing through speakers/HDMI is picked up and analyzed

Limitations:

  • Requires Apple TV 4K (has built-in mic for Siri)
  • Audio quality depends on room acoustics
  • Background noise can affect analysis
  • Slight latency (~50ms) between playback and visual response

Alternative approaches investigated:

  1. AVAudioEngine tap on outputNode — crashes because MusicKit owns the audio session
  2. MTAudioProcessingTap — requires AVPlayer/AVPlayerItem, not compatible with MusicKit
  3. AVAudioPlayerNode with MusicKit stream — MusicKit doesn't expose a stream URL

Fallback: When no microphone is available (e.g., Simulator), the app runs in simulated mode with procedurally generated audio data that produces plausible visualization behavior.

3. Visual Rendering — Metal

Full-screen Metal rendering at native resolution/refresh rate.

  • MTKView as the primary rendering surface
  • Fragment shader per visual mode (fullscreen quad approach)
  • Reads AudioAnalysisData every frame via shared Uniforms struct
  • ~1.5 second crossfade transition when switching modes
  • Zero UI chrome during visualization — full bleed edge to edge

Visual Modes

#NameCharacter
0C-240Lissajous curves, CRT-era colors, analog warmth. Homage to the original.
1MembraneOrganic undulating surface, bass deformation, spectral color shifts
2Particle FieldThousands of particles, transient bursts, gravity wells, fading trails
3TunnelRaymarched wormhole, amplitude-driven velocity, beat-synced color cycling
4Glitch GridHard-edged geometric grid, transient displacement, color inversion
5DriftSlow-evolving noise nebula, minimal audio reactivity, ambient background

Every mode includes a drift parameter — slow autonomous evolution that prevents static-looking output even when audio is steady.


Siri Remote Controls

InputAction
Play/Pause buttonPlay/pause music
Left on clickpadPrevious track
Right on clickpadNext track
Up on clickpadNext visual mode
Down on clickpadPrevious visual mode
Menu buttonShow/hide music browser
Select (center click)Show Now Playing info briefly

Screensaver Behavior

tvOS does not expose a public API for third-party screensaver registration. Instead, the app implements auto-dim simulation:

  • After 30 seconds of no remote input, all UI is hidden
  • The visualizer runs full-screen without any overlays
  • If music is playing, it visualizes the music
  • If no music is playing, the current mode runs with drift-only motion (ambient behavior)
  • Any remote interaction immediately exits screensaver mode

Project Structure

VideoMusic/
├── VideoMusic.xcodeproj
├── VideoMusic.entitlements # MusicKit entitlement
├── VideoMusic/
│ ├── VideoMusic-Bridging-Header.h # Exposes ShaderTypes.h to Swift
│ ├── App/
│ │ ├── VideoMusicApp.swift # @main app entry point
│ │ └── ContentView.swift # Root view — orchestrates all systems
│ ├── Music/
│ │ ├── MusicManager.swift # MusicKit auth, library, playback
│ │ ├── MusicBrowserView.swift # Album/playlist/search browser UI
│ │ └── NowPlayingView.swift # Now Playing overlay (auto-fades)
│ ├── Audio/
│ │ ├── AudioEngine.swift # AVAudioEngine setup + mic loopback
│ │ ├── AudioAnalysisData.swift # Shared audio data (thread-safe)
│ │ └── FFTProcessor.swift # vDSP FFT + band extraction
│ ├── Visual/
│ │ ├── VisualRenderer.swift # MTKView + Metal pipeline
│ │ ├── ShaderTypes.h # Shared Swift/Metal data types
│ │ ├── ModeTransitionManager.swift # Crossfade between modes
│ │ └── Shaders/
│ │ ├── C240Mode.metal # Mode 0 + shared vertex shader
│ │ ├── MembraneMode.metal # Mode 1
│ │ ├── ParticleMode.metal # Mode 2
│ │ ├── TunnelMode.metal # Mode 3
│ │ ├── GlitchGridMode.metal # Mode 4
│ │ └── DriftMode.metal # Mode 5
│ ├── Remote/
│ │ └── RemoteInputHandler.swift # Siri Remote via GameController
│ └── Resources/
│ ├── Assets.xcassets
│ └── Info.plist
└── README.md

Tech Stack

ComponentTechnology
LanguageSwift 5, Metal Shading Language
UISwiftUI
MusicMusicKit (ApplicationMusicPlayer)
Audio AnalysisAVFoundation, AVFAudio, Accelerate (vDSP)
RenderingMetal, MetalKit
InputGameController framework
TargettvOS 17.0+
DeviceApple TV 4K (all generations)

Setup

  1. Open VideoMusic.xcodeproj in Xcode 15+
  2. In the project's Signing & Capabilities:
    • Set your Development Team
    • The MusicKit capability should already be configured
  3. In the Apple Developer Portal:
    • Register the App ID com.fladrycreative.videomusic
    • Enable the MusicKit App Service
  4. Build and run on Apple TV Simulator or a real Apple TV 4K
  5. On first launch, approve the Apple Music access prompt

Note: The Simulator will run in simulated audio mode (no microphone). For real audio-reactive behavior, deploy to a physical Apple TV 4K.


For Shader Artists

The shaders are the soul of this app and will be iterated heavily. Here's what you need to know:

Data Flow

Audio → FFTProcessor → AudioAnalysisData → Uniforms (CPU) → Fragment Shader (GPU)

Every fragment shader receives a Uniforms struct containing:

  • All 5 frequency bands + amplitude + transient + spectral centroid
  • Time, delta time, resolution
  • Current mode, transition progress
  • Drift parameter (slow autonomous evolution)

Editing Shaders

  1. Each mode is a self-contained .metal file
  2. The shared vertex shader lives in C240Mode.metal
  3. ShaderTypes.h defines the Uniforms struct — shared between Swift and Metal
  4. Fragment function naming convention: fragment[ModeName] (e.g., fragmentC240)
  5. All modes receive the same Uniforms data — the difference is how they interpret it

Adding a New Mode

  1. Create NewMode.metal in Visual/Shaders/
  2. Add the fragment function (follow existing patterns)
  3. Add the fragment name to the fragmentNames array in VisualRenderer.swift
  4. Increment modeCount in ModeTransitionManager.swift
  5. Add the mode name to modeNames array
  6. Add the enum case in ShaderTypes.h

What's NOT Included (Coming Later)

  • Companion iOS/watchOS app
  • OSC / network / external control
  • Settings screen or preferences
  • Social features, sharing, or recording
  • In-app purchases or monetization

License

Copyright 2026 Fladry Creative. All rights reserved.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages