MixBoard is a native macOS music player and mixtape builder built with Swift, SwiftUI, and SwiftData. It's designed for DJs and music curators who want to listen to music, curate playlists, and export mixes for further editing in DAWs like Adobe Audition.
PlaylistViewConfig is a singleton (PlaylistViewConfig.shared) to keep the player bar cursor-mode button and playlist view context menu in sync.sesx exporter is reverse-engineered from real Audition files but may not work with all Audition versions# Build and launch the app (no Xcode GUI needed):
cd /Users/vdrobkov/Misc/Documents/Copilot/MixBoard
pkill -f MixBoard 2>/dev/null; sleep 0.5
xcodegen generate 2>&1 | tail -1
xcodebuild -project MixBoard.xcodeproj -scheme MixBoard -destination 'platform=macOS' build 2>&1 | tail -3
open /Users/vdrobkov/Library/Developer/Xcode/DerivedData/MixBoard-hfuiayempdyihjaigvvglaqkkkth/Build/Products/Debug/MixBoard.app
MANDATORY: After implementing any new feature or changing any existing feature:
Tests are split into:
Tests/Unit/) — model, service, exporter, filename template, app state testsTests/E2E/) — full workflow tests (player load/play/pause/stop/seek, playlist next/prev/shuffle/repeat, import→playlist→export, stitch with markers, theme persistence, config persistence, quick-add, duplicate detection, track notes, drag-to-playlist)All tests run as hosted unit tests (inside the app process) — no UI automation needed. Currently 99 tests, 0 failures.
# Run all tests (unit + E2E):
xcodebuild -project MixBoard.xcodeproj -scheme MixBoardTests -destination 'platform=macOS' test 2>&1 | grep "Executed" | tail -2
# Run tests with failure details:
xcodebuild -project MixBoard.xcodeproj -scheme MixBoardTests -destination 'platform=macOS' test 2>&1 | grep -E "passed|failed|Executed" | tail -20
After adding or removing source files, always regenerate:
xcodegen generate
Sources/
├── MixBoardApp.swift # App entry, menu commands, keyboard shortcuts
├── Models/
│ ├── Track.swift # @Model — audio track with metadata
│ ├── CuePoint.swift # @Model — markers on tracks
│ ├── Playlist.swift # @Model — ordered collection of entries
│ ├── PlaylistFolder.swift # @Model — groups playlists in sidebar
│ ├── PlaylistViewConfig.swift # Column visibility, grouping, cursor mode (singleton)
│ ├── AppTheme.swift # 13 skins, all colors/sizes (ObservableObject)
│ ├── AppState.swift # UserDefaults persistence for last playlist/track/position
│ └── FileNameTemplate.swift # Configurable export file naming ({artist}, {title}, etc.)
├── Services/
│ ├── AudioEngine.swift # AVAudioEngine playback, seek, route change handling
│ ├── BPMDetector.swift # Spectral flux + autocorrelation BPM detection
│ ├── KeyDetector.swift # Chromagram + key profile matching
│ ├── WaveformGenerator.swift # Downsampled min/max waveform data
│ ├── MetadataService.swift # AVFoundation metadata reading
│ ├── LibraryManager.swift # File import, analysis, file operations
│ ├── ArtworkService.swift # Folder artwork loading (foobar2000 style)
│ └── MediaKeyHandler.swift # MPRemoteCommandCenter integration
├── Export/
│ ├── DAWExporter.swift # Protocol, ExportOptions, MixExporter dispatcher
│ ├── AuditionExporter.swift # Real .sesx format with absolute file paths
│ ├── AudioStitcher.swift # Concatenate to single WAV + markers CSV/CUE
│ ├── CueSheetExporter.swift # Standard .cue format
│ ├── EDLExporter.swift # CMX 3600 EDL
│ ├── DAWProjectExporter.swift # Open DAWproject format
│ └── M3UExporter.swift # M3U playlist
├── ViewModels/
│ ├── PlayerViewModel.swift # @Observable — playback state, next/prev, shuffle/repeat
│ └── PlaylistViewModel.swift # @Observable — CRUD, quick-add, duplicate detection, status
└── Views/
├── ContentView.swift # Main layout, state restore, status toast
├── SidebarView.swift # Playlists + folders, drag/drop, target playlist
├── PlaylistView.swift # Track list, column headers, configurable rows, context menu
├── PlayerView.swift # Transport, shuffle/repeat, cursor mode, seekbar, volume, skin picker
├── ExportSheet.swift # Session export + stitch export tabs, file naming template
├── GlobalSearchSheet.swift # Search across all playlists
├── WaveformView.swift # Interactive waveform canvas
├── ArtworkView.swift # Async folder/embedded artwork loading
└── TrackRow.swift # Compact track display
Tests/
├── Unit/
│ ├── ModelTests.swift # Track, CuePoint, Playlist, PlaylistEntry, PlaylistFolder, AppTheme, AppState
│ ├── ServiceTests.swift # MetadataService, WaveformGenerator, BPMDetector, KeyDetector
│ ├── ExporterTests.swift # All 5 export formats
│ └── FileNameTemplateTests.swift # Template generation, variables, sanitization, presets
├── E2E/
│ ├── E2EWorkflowTests.swift # Import→playlist→export, stitch, analysis, multi-format
│ └── IntegrationTests.swift # Player VM flows, shuffle/repeat, export, quick-add, duplicates, notes
└── Helpers/
└── TestHelpers.swift # Test audio file generation (sine wave WAVs)
@Observable (not ObservableObject) for new ViewModels@EnvironmentObject for ObservableObject types (LibraryManager, AppTheme)@Environment for @Observable types (PlayerViewModel, PlaylistViewModel)PlaylistViewConfig.shared — it's a singleton, don't create new instancesColor.accentColor (not .accentColor) in ternary expressions to avoid ShapeStyle type errorsxcodebuild over swift build for the final build (SwiftData macros require Xcode toolchain)xcodegen generate before buildingplaybackGeneration counter to prevent completion handler race conditions.dataPlayedBack (not default .dataConsumed) for AVAudioPlayerNode completion handlersxcodebuild over swift build for the final build (SwiftData macros require Xcode toolchain)