This document describes the technical architecture and design of BitPerfectCore, the bit-perfect audio playback engine for macOS.
BitPerfectCore is designed as a modular, high-performance audio engine that provides true bit-perfect playback on macOS. The architecture prioritizes audio quality, performance, and reliability while maintaining a clean, Swift-idiomatic API.
- No audio processing or modification in the playback path
- Direct hardware access via CoreAudio HAL
- Sample rate matching to avoid resampling
- Exclusive device access when needed
- Minimal CPU overhead
- Efficient buffer management
- Low-latency audio path
- Optimized for modern Apple Silicon and Intel Macs
- Robust error handling
- Graceful degradation
- Thread-safe operations
- Comprehensive testing
- Clean separation of concerns
- Protocol-oriented design
- Pluggable components
- Easy to extend and maintain
- Modern Swift idioms
- Type safety
- Async/await support
- SwiftUI integration ready
┌─────────────────────────────────────────────────────────────┐
│ Client Application │
│ (Perfecta) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ BitPerfectCore Public API │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ BitPerfect │ │ Audio │ │ Format │ │
│ │ Engine │ │ Device │ │ Decoder │ │
│ │ │ │ Manager │ │ Protocol │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Core Components Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Audio │ │ Sample │ │ Buffer │ │
│ │ Renderer │ │ Rate │ │ Manager │ │
│ │ │ │ Matcher │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Format │ │ Metadata │ │ Gapless │ │
│ │ Decoders │ │ Extractor │ │ Player │ │
│ │ │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ CoreAudio HAL Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Device │ │ Stream │ │ Hardware │ │
│ │ Access │ │ Config │ │ Control │ │
│ │ │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Audio Hardware (DAC) │
└─────────────────────────────────────────────────────────────┘
Purpose: Main entry point and orchestrator for bit-perfect audio playback.
Responsibilities:
- Initialize and configure the audio pipeline
- Manage playback state (play, pause, stop)
- Coordinate between components
- Handle errors and state transitions
Key APIs:
class BitPerfectEngine {
func configure(device: AudioDevice, format: AudioFormat) throws
func play(url: URL) async throws
func pause()
func stop()
func seek(to position: TimeInterval) throws
var isPlaying: Bool { get }
var currentTime: TimeInterval { get }
var duration: TimeInterval { get }
}Purpose: Manage audio devices and their configurations.
Responsibilities:
- Enumerate available audio devices
- Query device capabilities
- Configure device settings
- Monitor device changes (hot-plug)
Key APIs:
class AudioDeviceManager {
func enumerateDevices() -> [AudioDevice]
func defaultDevice() -> AudioDevice?
func device(withID id: AudioDeviceID) -> AudioDevice?
func setDefaultDevice(_ device: AudioDevice) throws
var deviceChangePublisher: AnyPublisher<AudioDeviceChange, Never> { get }
}
struct AudioDevice {
let id: AudioDeviceID
let name: String
let manufacturer: String
let supportedSampleRates: [Double]
let supportedBitDepths: [Int]
let channels: Int
let isDefault: Bool
}Purpose: Direct audio rendering to hardware.
Responsibilities:
- Interface with CoreAudio HAL
- Manage audio buffers
- Handle exclusive device access
- Ensure bit-perfect output
Key APIs:
class AudioRenderer {
func initialize(device: AudioDevice, format: AudioFormat) throws
func start() throws
func stop()
func render(buffer: AudioBuffer) throws
var isExclusiveMode: Bool { get }
var actualSampleRate: Double { get }
}Purpose: Match device sample rate to source material.
Responsibilities:
- Detect source sample rate
- Configure device sample rate
- Validate sample rate compatibility
- Handle sample rate changes
Key APIs:
class SampleRateManager {
func detectSourceRate(from url: URL) throws -> Double
func matchDeviceRate(device: AudioDevice, to sampleRate: Double) throws
func validateCompatibility(device: AudioDevice, sampleRate: Double) -> Bool
}Purpose: Unified interface for audio format decoding.
Responsibilities:
- Decode audio files to PCM
- Extract audio metadata
- Support multiple formats
- Efficient streaming
Key APIs:
protocol FormatDecoder {
func canDecode(url: URL) -> Bool
func decode(url: URL) throws -> AudioStream
func metadata(from url: URL) throws -> AudioMetadata
}
// Implementations:
class FLACDecoder: FormatDecoder { }
class ALACDecoder: FormatDecoder { }
class WAVDecoder: FormatDecoder { }
class AIFFDecoder: FormatDecoder { }
class DSDDecoder: FormatDecoder { }Purpose: Efficient audio buffer management.
Responsibilities:
- Allocate and manage audio buffers
- Handle buffer queuing
- Optimize memory usage
- Prevent buffer underruns
Key APIs:
class BufferManager {
func allocateBuffer(size: Int) -> AudioBuffer
func enqueueBuffer(_ buffer: AudioBuffer)
func dequeueBuffer() -> AudioBuffer?
func clear()
var bufferCount: Int { get }
var isBufferReady: Bool { get }
}Purpose: Seamless track transitions.
Responsibilities:
- Pre-buffer next track
- Seamless transitions
- Handle format changes
- Maintain playback continuity
Key APIs:
class GaplessPlayer {
func enqueueTrack(url: URL) throws
func prepareNextTrack() async throws
func transitionToNext() throws
var currentTrack: URL? { get }
var nextTrack: URL? { get }
}Purpose: Extract audio file metadata.
Responsibilities:
- Read ID3, Vorbis, APE tags
- Extract embedded artwork
- Parse audio properties
- Support multiple formats
Key APIs:
class MetadataExtractor {
func extract(from url: URL) throws -> AudioMetadata
}
struct AudioMetadata {
let title: String?
let artist: String?
let album: String?
let albumArtist: String?
let genre: String?
let year: Int?
let trackNumber: Int?
let artwork: Data?
let duration: TimeInterval
let sampleRate: Double
let bitDepth: Int
let channels: Int
let bitrate: Int?
}
┌──────────────┐
│ Audio File │
└──────┬───────┘
│
▼
┌──────────────┐
│ Format │ ─── Detect format
│ Decoder │ ─── Decode to PCM
└──────┬───────┘
│
▼
┌──────────────┐
│ Sample │ ─── Match device rate
│ Rate │ ─── Configure hardware
│ Matcher │
└──────┬───────┘
│
▼
┌──────────────┐
│ Buffer │ ─── Queue audio buffers
│ Manager │ ─── Prevent underruns
└──────┬───────┘
│
▼
┌──────────────┐
│ Audio │ ─── Render to hardware
│ Renderer │ ─── Bit-perfect output
└──────┬───────┘
│
▼
┌──────────────┐
│ Hardware │
│ DAC │
└──────────────┘
- Public API calls
- State management
- UI updates (via callbacks/publishers)
- Audio rendering
- Buffer management
- CoreAudio callbacks
- Must be lock-free and deterministic
- File I/O
- Audio decoding
- Metadata extraction
- Buffer preparation
- Device enumeration
- Hot-plug detection
- Configuration changes
enum BitPerfectError: Error {
case deviceNotFound
case deviceNotAvailable
case unsupportedFormat
case unsupportedSampleRate
case exclusiveModeUnavailable
case bufferUnderrun
case decodingError(underlying: Error)
case hardwareError(underlying: Error)
}- Graceful Degradation: Fall back to non-exclusive mode if needed
- Retry Logic: Attempt recovery for transient errors
- User Notification: Report errors via callbacks/publishers
- Logging: Comprehensive error logging for debugging
- Use ARC for Swift objects
- Manual memory management for audio buffers (performance)
- Pool audio buffers to avoid allocations
- Release resources promptly
- Pre-allocate buffer pool at initialization
- Reuse buffers to avoid allocations during playback
- Use page-aligned memory for optimal performance
- Monitor memory usage and adjust pool size
- CPU Usage: < 5% on modern Macs during playback
- Latency: < 10ms from decode to output
- Memory: < 50MB for typical playback
- Buffer Underruns: Zero under normal conditions
- Lock-free audio thread
- SIMD optimizations where applicable
- Efficient buffer management
- Lazy initialization
- Minimal allocations in hot paths
- Individual component testing
- Mock CoreAudio interfaces
- Edge case coverage
- Performance benchmarks
- End-to-end playback tests
- Multi-format validation
- Device switching tests
- Error recovery tests
- Bit-perfect verification (loopback)
- Sample rate accuracy
- Latency measurements
- CPU profiling
Key APIs Used:
AudioObjectGetPropertyData- Query device propertiesAudioDeviceCreateIOProcID- Create audio callbackAudioDeviceStart/Stop- Control playbackAudioObjectAddPropertyListener- Monitor changes
Exclusive Mode:
- Use
kAudioDevicePropertyHogModeto take exclusive control - Bypass system audio processing
- Direct hardware access
Sample Rate Matching:
- Query
kAudioDevicePropertyNominalSampleRate - Set device sample rate to match source
- Verify actual rate after configuration
- Multi-channel audio support (5.1, 7.1)
- DSD native playback
- Network audio streaming
- Room correction integration
- Plugin architecture for custom processors
- Cross-platform support (iOS, Linux)
- MQA decoding
- High sample rate optimization (384kHz+)
- Low-latency monitoring
- Audio analysis and visualization
- Hardware-accelerated decoding
- CoreAudio - Audio hardware access
- AVFoundation - Audio format support
- Accelerate - SIMD optimizations
- libFLAC - FLAC decoding
- libsndfile - Multi-format support
- TagLib - Metadata extraction
- Swift-First: Idiomatic Swift API
- Type-Safe: Leverage Swift's type system
- Async-Ready: Support async/await
- Publisher-Based: Use Combine for reactive updates
- Error-Explicit: Clear error handling
- Documentation: Comprehensive inline docs
import BitPerfectCore
// Initialize engine
let engine = BitPerfectEngine()
// Configure device
let deviceManager = AudioDeviceManager()
let devices = deviceManager.enumerateDevices()
let dac = devices.first { $0.name.contains("DAC") }
try engine.configure(device: dac!)
// Play audio
try await engine.play(url: audioFileURL)
// Monitor state
engine.statePublisher
.sink { state in
print("Playback state: \(state)")
}
.store(in: &cancellables)- MAJOR: Breaking API changes
- MINOR: New features, backward compatible
- PATCH: Bug fixes, backward compatible
- Public API marked with
@available - Deprecation warnings before removal
- Migration guides for breaking changes
- All public APIs documented with DocC
- Usage examples in documentation
- Parameter descriptions
- Return value descriptions
- Error conditions documented
- This document (ARCHITECTURE.md)
- Component diagrams
- Sequence diagrams
- API reference (generated)
Last Updated: June 2026
Version: 0.5.0
Author: Mario Alberto Arce