Skip to content

Commit 8e4c942

Browse files
committed
ToooT 1.0
0 parents  commit 8e4c942

67 files changed

Lines changed: 11606 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
build-and-test:
11+
runs-on: macos-15
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Select Xcode 16 (Swift 6)
16+
run: sudo xcode-select -s /Applications/Xcode_16.0.app
17+
18+
- name: Build Project
19+
run: swift build
20+
21+
- name: Run Validation Suite (UAT)
22+
run: .build/arm64-apple-macosx/debug/UATRunner

.gitignore

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Xcode / Swift
2+
.build/
3+
.swiftpm/
4+
*.xcodeproj
5+
*.xcworkspace
6+
xcuserdata/
7+
*.xcframework
8+
DerivedData/
9+
*.app/
10+
*.app
11+
12+
# OS X
13+
.DS_Store
14+
.AppleDouble
15+
.LSOverride
16+
17+
# Testing / Diagnostic Media
18+
*.wav
19+
*.aiff
20+
*.mp3
21+
*.m4a
22+
*.jpg
23+
*.png
24+
25+
# Diagnostic & Refactor Scripts
26+
*.py
27+
waveform_compare/
28+
29+
# Temporary / Session Outputs
30+
uat_output.txt
31+
deep_project_session.json
32+
deep_project_interview.md
33+
gemini_prompt_*.md
34+
gemini.md
35+
refactor.py
36+
refactor2.py
37+
fix_*.py
38+
strip_focus.py
39+
40+
# Internal Project Docs
41+
AUDIT.md
42+
HANDOFF.md
43+
project-manifest.md
44+
requirements.md
45+
SESSION_LOG.md

01-audio-engine-perf/spec.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Spec: 01-audio-engine-perf
2+
3+
**Project:** ProjectToooT — macOS 2026 Native DAW
4+
**Module:** ToooT_Core
5+
**Track:** Parallel A (independent of UI and I/O work)
6+
7+
## Goal
8+
9+
Eliminate the two biggest CPU bottlenecks in the audio render path, targeting Apple Silicon M-series efficiency. Core audio is already production quality (17 UAT suites passing) — this is pure performance work.
10+
11+
## Background
12+
13+
See `requirements.md` §2 (Core Audio Engine) and `memory/project_status.md` §Known Performance Gaps.
14+
15+
The engine is correct but has two known scalar hotspots:
16+
17+
1. **SynthVoice resampler** — 4-point Hermite interpolation implemented as a per-sample scalar loop. Target: `vDSP_vlint` vectorized path.
18+
2. **AudioRenderNode channel iteration** — iterates all available channels (up to 1024 per requirements, 256 per current build) every render cycle even when most are empty. Target: active-channel bitmask.
19+
20+
## What to Build
21+
22+
### Task A: Vectorize SynthVoice Resampler
23+
- Replace the per-sample Hermite loop in `SynthVoice.process()` with `vDSP_vlint`
24+
- **Critical OOB guard (L32):** `vDSP_vlint` reads `floor(i)` and `floor(i)+1`. For resample factor F, source count N: `maxNewCount = (N-1) / F`. Cap `newCount = min(maxNewCount, N/F)`. Off-by-one causes silent memory corruption.
25+
- Maintain loop wrapping for ping-pong and reverse looping modes (L27: loop bounds check must gate behind `!isLooping`; Hermite lookahead indices must wrap around loop region, not clamp to `sampleLength-1`)
26+
- Validate interpolation quality: octave-down should produce 439–440 zero-crossings (test 16 baseline)
27+
28+
### Task B: Active-Channel Bitmask in AudioRenderNode
29+
- Add a bitmask (e.g., `UInt64` array or `[Bool]`) tracking which channels have active voices
30+
- Update the bitmask atomically when voices are triggered or complete (RT-safe, no locking)
31+
- Skip empty channels in the render loop without iterating their DSP path
32+
- The shared render logic lives in `processTickSequencer(wrapOnEnd:)` (L33) — do not duplicate any logic; changes here apply to both `renderBlock` and `renderOffline`
33+
34+
## Constraints
35+
36+
- **No heap allocation on the render thread** — bitmask must be pre-allocated; `vDSP_vlint` buffers must be pre-allocated from the UMA slab or stack
37+
- **Swift 6 strict concurrency** — bitmask writes must be `Atomic<T>` or happen only on the audio thread
38+
- **masterVol = 0.5** (L26) — do not change the gain constant
39+
- **Oscillating effects must not write back to base properties** (L24) — do not touch tremolo/vibrato paths
40+
- **UAT must stay green** — all 17 suites must pass after changes; waveform correlation ≥ 0.99 (test 15)
41+
42+
## Success Criteria
43+
44+
- [ ] `vDSP_vlint` resampler implemented with correct OOB guard
45+
- [ ] Active-channel bitmask skips empty channels in render loop
46+
- [ ] All 17 UAT suites pass
47+
- [ ] Perf microbenchmark: cycles-per-frame reduced measurably (establish baseline before starting)
48+
- [ ] No new Swift 6 concurrency warnings
49+
50+
## Dependencies
51+
52+
**Needs from other splits:** None — fully self-contained in ToooT_Core.
53+
**Provides to other splits:** Stable `EngineSharedState` snapshot API (used by 03-ui-coherence for playhead animation).

02-io-save-load/spec.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Spec: 02-io-save-load
2+
3+
**Project:** ProjectToooT — macOS 2026 Native DAW
4+
**Module:** ToooT_IO
5+
**Track:** Parallel B (independent of audio perf and UI work)
6+
7+
## Goal
8+
9+
Make project save/load lossless and production-ready. A DAW that cannot save its own projects cannot be demoed at WWDC. This is a critical early deliverable.
10+
11+
## Background
12+
13+
See `requirements.md` §3 (I/O & Standards) and `memory/project_status.md` §Stubs / Incomplete.
14+
15+
The parsing side (MADParser, FormatTranspiler) is largely working — MOD/XM/IT all load, finetune is read correctly (L29). The write side has known gaps:
16+
17+
- `MADWriter` saves hardcoded "ToooT Project" as title regardless of loaded song
18+
- `MADWriter` does not serialize finetune back to header byte 24 lower nibble
19+
- MIDI import has a basic parser but needs better track/channel mapping
20+
21+
## What to Build
22+
23+
### Task A: MADWriter Lossless Round-Trip
24+
- Serialize actual song title from the loaded `MADMusic` / `UnifiedSampleBank` metadata
25+
- Write finetune back to instrument header byte 24, lower nibble (values -8 to +7, two's complement nibble)
26+
- This is the inverse of the L29 parse: `pow(2, finetune/96.0)` — the nibble value must survive round-trip
27+
- Verify all `UnifiedSampleBank` PCM data is serialized (requirements §3: "zero-loss project saving")
28+
- Add regression test: load a reference MOD file, save it, reload it, assert:
29+
- Song title matches
30+
- Finetune nibble byte-for-byte identical
31+
- Audio output waveform correlation ≥ 0.99 against original
32+
33+
### Task B: MADParser Dynamic Sample Offsets
34+
- Requirements §3: `MADParser` must support dynamic sample offsets and lengths for third-party MOD/MAD files
35+
- Audit current parser for hardcoded offset assumptions; fix any that fail on non-canonical files
36+
37+
### Task C: MIDI Import Track/Channel Mapping
38+
- Current state: basic MIDI parser exists, stub-level track/channel mapping
39+
- Improve: map MIDI tracks to channels intelligently (by program, by track name, by channel number)
40+
- Minimum: load a standard General MIDI file and have each track land in the correct tracker channel
41+
42+
## Constraints
43+
44+
- **Do not break existing UAT** — MOD/XM/IT load tests (suites 1–14+) must all remain green
45+
- **Finetune formula is fixed** (L29): `pow(2, finetune/96.0)` — do not alter the math
46+
- **MADParser must support dynamic offsets** per requirements §3 — no hardcoded byte positions
47+
- **MIDI 2.0 is out of scope here** — that belongs to 05-platform-hardening; this split targets standard MIDI import
48+
49+
## Success Criteria
50+
51+
- [ ] MADWriter serializes actual song title
52+
- [ ] MADWriter writes finetune nibble; byte-for-byte verified round-trip test passes
53+
- [ ] All existing UAT suites remain green
54+
- [ ] At least one real-world third-party MOD file loads correctly with dynamic offsets
55+
- [ ] A standard MIDI file imports with recognizable track/channel assignment
56+
57+
## Dependencies
58+
59+
**Needs from other splits:** None — fully self-contained in ToooT_IO.
60+
**Provides to other splits:** Lossless save/load foundation that 03-ui-coherence's "Save Project" UI depends on.

03-ui-coherence/spec.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Spec: 03-ui-coherence
2+
3+
**Project:** ProjectToooT — macOS 2026 Native DAW
4+
**Module:** ToooT_UI + ProjectToooTApp
5+
**Track:** Main (largest split — start immediately, runs alongside 01 and 02)
6+
7+
## Goal
8+
9+
Stabilize and integrate all ToooT_UI views into a coherent, fully functional DAW workspace. Every major view must open, render correctly, respond to user input, and stay wired to the engine. No crashes on view switch. WWDC target: full DAW feature parity in a single session.
10+
11+
## Background
12+
13+
See `requirements.md` §5 (User Experience & Interface), `memory/project_status.md` §Working Features and §Stubs.
14+
15+
Interview finding: "broken UI" is all views simultaneously — Metal grid, Piano Roll, Envelope Editor, Automation, Spatial Visualizer. This is an integration coherence problem, not isolated component bugs.
16+
17+
## What to Build
18+
19+
Work through these views in priority order (each must be stable before moving to the next):
20+
21+
### 1. TrackerWorkspace Layout
22+
- Window management: persistent layout state across launches
23+
- Navigation between views (pattern grid ↔ piano roll ↔ envelope ↔ automation ↔ spatial) without state loss
24+
- Toolbar / transport controls always visible and functional
25+
26+
### 2. Metal Pattern Grid
27+
- Verify 120Hz ProMotion via `MTKView` (not timer-based redraws — use display link)
28+
- GPU-instanced cell rendering: thousands of cells, minimal CPU overhead
29+
- Arrow navigation, note entry (Z–M keyboard layout), Cmd+C/V row copy-paste, Cmd+D duplicate — all must work
30+
- Playhead animation must read **only** from `sharedState.playheadPosition` (L25) — never derive from `samplesProcessed`
31+
32+
### 3. Piano Roll
33+
- Drag-to-paint note entry: erase mode on existing notes, paint mode on empty space
34+
- Multi-touch trackpad support
35+
- Visual velocity feedback per note
36+
- Stable undo/redo integration (50 levels)
37+
38+
### 4. Envelope Editor
39+
- Volume / pan / pitch envelope types
40+
- Drag existing points, click background to add, right-click to delete
41+
- Points must bind bidirectionally to engine envelope state
42+
43+
### 5. Automation Editor
44+
- Draggable Bezier curves for all automatable parameters
45+
- Implemented via SwiftUI `Canvas` + `DragGesture`
46+
- Binds to `EngineSharedState` parameter slots
47+
48+
### 6. Spatial Visualizer
49+
- 3D source positioning via drag
50+
- **Bidirectional:** dragging in UI must update `SpatialManager` / PHASE in real-time
51+
- `SpatialManager` position changes (e.g., from automation) must reflect in UI
52+
53+
### 7. Mixer
54+
- Real-time level meters wired to render output (read from `EngineSharedState` snapshot)
55+
- AUv3 insert rack visible: Stereo Wide + Pro Reverb slots
56+
57+
### 8. Video Sync
58+
- `ScreenCaptureKit` feed displayed
59+
- Sequencer playhead hard-synced to video playback position (`AVFoundation` timecode)
60+
61+
## UI/UX Philosophy (Apple Silicon Performance)
62+
63+
- **Metal-first rendering:** Pattern grid and any timeline component must use Metal (`MTKView`) — no CoreGraphics fallback in hot paths
64+
- **ProMotion-adaptive:** Tie render loop to `CADisplayLink` / `MTKView` preferred frame rate (120Hz on ProMotion displays, graceful fallback)
65+
- **One atomic bridge:** `EngineSharedState` is the only legal read path from UI to engine — take a snapshot per frame, never dereference live audio-thread pointers from `@MainActor` code
66+
- **SwiftUI for controls, Metal for grids:** SwiftUI `Canvas` + gestures for Automation Bezier; Metal instanced rendering for the tracker grid and piano roll keys
67+
- **Playhead as truth:** All animations derive from `sharedState.playheadPosition` (L25) — a `Float` written by the render block as `Float(row) + Float(tick)/Float(ticksPerRow)`
68+
69+
## Critical Rules (Must Not Violate)
70+
71+
| Rule | Source |
72+
|---|---|
73+
| Never write UI-owned BPM/tempo to engine during playback | L21 |
74+
| Playhead position = `sharedState.playheadPosition` only | L25 |
75+
| Tremolo/vibrato: transient display values only, never stored in view model | L24 |
76+
| All `@MainActor` UI must use `EngineSharedState` snapshot — no direct audio struct access | Swift 6 |
77+
| StereoWide reads both channels from a scratch copy before computing newL/newR | L23 |
78+
79+
## Constraints
80+
81+
- **Swift 6 strict concurrency** — all UI code must be `@MainActor`; no `@unchecked Sendable`
82+
- **No timer-based redraws** — use display link or `onChange` driven by `EngineSharedState` published snapshot
83+
- **Undo/Redo must survive view switches** — 50-level stack must not be scoped to a single view
84+
85+
## Success Criteria
86+
87+
- [ ] All 8 views open without crashing
88+
- [ ] Metal grid renders at 120Hz; playhead animates smoothly during playback
89+
- [ ] Piano Roll: paint/erase notes, undo/redo works
90+
- [ ] Envelope Editor: add/move/delete points, changes persist
91+
- [ ] Automation: Bezier curves draggable, bound to engine params
92+
- [ ] Spatial Visualizer: drag source → PHASE position updates in real-time
93+
- [ ] Mixer: meters move during playback; AUv3 rack visible
94+
- [ ] Video Sync: playhead tracks video timecode
95+
- [ ] No Swift 6 concurrency warnings in ToooT_UI module
96+
97+
## Dependencies
98+
99+
**Needs from other splits:**
100+
- `EngineSharedState` snapshot API (stable after 01-audio-engine-perf, but can work against current version)
101+
- Lossless save/load (02-io-save-load) for "Save Project" menu item
102+
103+
**Provides to other splits:**
104+
- Stable `TrackerWorkspace` scaffold that 04-neural-ane-acceleration's synthesis UI slots into

04-neural-ane-acceleration/spec.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Spec: 04-neural-ane-acceleration
2+
3+
**Project:** ProjectToooT — macOS 2026 Native DAW
4+
**Module:** ToooT_Core (synthesis) + ToooT_UI (synthesis panel)
5+
**Track:** Parallel C (independent of UI coherence work)
6+
7+
## Goal
8+
9+
Accelerate the 6 working neural synthesis modules onto the Apple Neural Engine (ANE) and polish their UI integration. The modules already produce correct audio — this split is about performance acceleration and WWDC-quality presentation of the unique synthesis tiers.
10+
11+
## Background
12+
13+
See `requirements.md` §7 (Neural Engine & Algorithmic Synthesis) and `memory/project_status.md` §Working Features.
14+
15+
Interview finding: all 6 neural synthesis modules (BASSLINE, HARMONY, DRUMS, MARKOV MELODY, L-SYSTEM, SYNTH) are already functional. This is not ground-up implementation — it is ANE offloading, Markov cross-fade implementation, and synthesis tier UI.
16+
17+
The three synthesis tiers are brand identity — do not simplify or homogenize them:
18+
- **Carbon Tier:** electromagnetic interference, shorted logic gates, data corruption textures
19+
- **Biological Tier:** vocal fry, throat resonances, skeletal percussion, cardiac arrhythmia
20+
- **Xenomorph Tier:** fractal noise, cellular automata, "Void Screech" and "Quantum Foam"
21+
22+
## What to Build
23+
24+
### Task A: ANE Profiling and Offloading
25+
- Profile each of the 6 modules: identify which synthesis computation paths are ANE-suitable (matrix ops, convolution, inference)
26+
- Convert suitable paths to CoreML models or use `MLCompute` for ANE dispatch
27+
- **Critical constraint:** ANE inference must be fully async — results feed back into the synthesis pipeline without blocking or touching the audio render thread
28+
- Measure latency introduced by ANE round-trip; ensure it does not exceed one audio buffer period
29+
30+
### Task B: Markov Layer Cross-Fades
31+
- Implement Markov chain state transitions between synthesis tiers
32+
- Cross-fades driven by real-time `algSeed` data (read atomically from `EngineSharedState`)
33+
- Transition smoothness: `vDSP_vrampmul` for gain ramping during tier cross-fade (prevents clicks, per requirements §2)
34+
- State machine must be RT-safe: all `algSeed` reads are atomic; no locking on the audio thread
35+
36+
### Task C: Synthesis Tier UI Panel
37+
- Expose tier selection (Carbon / Biological / Xenomorph) in the synthesis panel within `TrackerWorkspace`
38+
- Real-time parameter display: show current `algSeed` value and active Markov state
39+
- Tier-specific parameter controls atoootpriate to each tier's character (e.g., "corruption intensity" for Carbon, "arrhythmia rate" for Biological)
40+
- UI writes to synthesis parameters must go through `EngineSharedState` atomic bridge (not direct struct mutation)
41+
42+
## Constraints
43+
44+
- **ANE inference is async only** — never block the audio render thread waiting for ANE output
45+
- **algSeed reads must be Atomic**`EngineSharedState.algSeed` accessed with `Atomic<T>` (Synchronization framework)
46+
- **Tier identity must be preserved** — do not normalize, soften, or simplify the Carbon/Biological/Xenomorph textures to make them "safer"
47+
- **Output feeds UnifiedSampleBank pipeline** — synthesis output format must be compatible with the existing sample bank PCM path
48+
- **Swift 6 strict concurrency** — synthesis UI panel follows same `@MainActor` rules as all other ToooT_UI code
49+
- **Minimum macOS 16** — required for latest ANE access via CoreML and Synchronization framework
50+
51+
## Success Criteria
52+
53+
- [ ] At least 2 of 6 modules have ANE-accelerated paths with measurable latency reduction
54+
- [ ] Markov cross-fades trigger correctly on `algSeed` change, no clicks or pops
55+
- [ ] Tier selection UI functional: switch between Carbon / Biological / Xenomorph live
56+
- [ ] ANE latency ≤ 1 audio buffer period (measured, not assumed)
57+
- [ ] All existing UAT suites still pass (synthesis changes must not break tracker audio)
58+
- [ ] No Swift 6 concurrency warnings in synthesis code paths
59+
60+
## Dependencies
61+
62+
**Needs from other splits:**
63+
- `UnifiedSampleBank` API (stable in current build — no dependency on other splits)
64+
- `TrackerWorkspace` scaffold for the synthesis UI panel (from 03-ui-coherence, but can stub during development)
65+
66+
**Provides to other splits:**
67+
- ANE-accelerated synthesis modules ready for 05-platform-hardening to validate under 24-hour load

0 commit comments

Comments
 (0)