Commit Graph
19 Commits
Author SHA1 Message Date
Brandon ThomasandClaude Opus 5.5 9ef525441a M7.7: audio-dsp: Premiere audio effect set (EQs, scientific/FFT filters, dynamics, multiband, modulation, delays, convolution/surround reverb, click remover, special/stereo)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 11:04:47 -04:00
Brandon ThomasandClaude Opus 5.5 9947fee359 M4.7: View menu and monitor view options: Paused Resolution, 1/16, High Quality Playback, Display Mode (alpha/RGB channels, comparison, multi-camera, source audio waveform, video+waveform split), Magnification with panning, rulers, guides (drag from rulers, lock, clear, Add Guide, templates in preferences), Snap in Program Monitor
MonitorView state is serde and settable with ui.set {program|source}; view.* UI commands with
menu checkmarks; wrench and zoom menus with automation ids; headless kittest tests (view_ui.rs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 23:23:27 -04:00
Brandon Thomas dc9c5fd32c Merge branch 'main' into worktree-agent-a98dbfec8c9b949c7 2026-10-01 13:06:51 -04:00
Brandon ThomasandClaude Opus 5.5 650a266352 M12.2: multicam and sync — Synchronize (In/Out/timecode ± hours/clip marker/audio), Merge Clips, Create Multi-Camera Source Sequence (camera names, audio camera 1/all/switch, Processed Clips bin), multi-camera clips (angle render, Switch Audio mix, GPU plan passthrough), switch angle / Ctrl+N cut / keys 1–9, live recording as one undo step, Enable/Flatten/Edit Cameras, audio follows video; nested sequence audio now plays; project schema v7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:08:45 -04:00
Brandon ThomasandClaude Opus 5.5 226c139741 M9.6: DNxHD/DNxHR (SMPTE ST 2019-1 VC-3) decoder and DNxHR encoder
New L0 crate filmcraft-dnx, written from SMPTE ST 2019-1:2016 + Amd 1:2023
(tables extracted from the standard's text by tools/extract_tables.py).

Decoder: every compression ID (DNxHD 1235-1260 incl. field-coded and
macroblock-adaptive interlace, thin rasters, RGB 4:4:4; DNxHR 1270-1274
LB/SQ/HQ/HQX/444), 8/10/12-bit, 4:2:0/4:2:2/4:4:4, DCT and lossless alpha,
macroblock rows in parallel. Matches ffmpeg within IDCT precision (max 2 LSB,
<=50 per million beyond 1, 87-99% identical) on 22 ffmpeg fixtures; follows
ffmpeg where it departs from the standard's text (reconstruction offset,
CID 1271 weights, 4:4:4 signalling) - documented in the README.

Encoder: DNxHR LB/SQ/HQ/HQX(10/12-bit)/444, CBR at the eq. 7.1 frame sizes,
uniform-qsf binary search + per-macroblock refinement; ffmpeg decodes every
profile with -xerror (HQ luma PSNR 58.8-66.3 dB).

Wiring: MOV AVdn/AVdh import (codec label from the CID), export
Format::DnxHr (MOV AVdh, dnxProfile lb|sq|hq|hqx) in the export dialog and
file.exportMedia.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:53:02 -04:00
Brandon ThomasandClaude Opus 5.5 a9af6fac71 Merge M8 (LUTs, colour management, Colour Match) into M4.6 playback; project schema v5 for colour management; architecture §5.3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:05:55 -04:00
Brandon Thomas c47c90f070 Merge branch 'main' into worktree-agent-a0342df5d4a386968 2026-10-01 09:03:47 -04:00
Brandon ThomasandClaude Opus 5.5 3dab45f45a M8.5: Colour Match (Lumetri ▸ Color Wheels & Match ▸ Apply Match) with skin-tone protection
- render::color_match: non-ML statistics matching — Oklab means per tonal range (smoothstep
  shadow/midtone/highlight weights) plus mean chroma; "Face Detection" down-weights skin-tone
  pixels (Oklab hue 20–75°) in the colour statistics and then limits the skin hue shift to 8°;
  the grade is solved in Lumetri's own parameters (3 wheels, their lightness, saturation) by
  damped Gauss–Newton through the real Lumetri implementation, so the result stays editable
- render::render_clip: one clip's layer at a time (the shot as Lumetri sees it)
- lumetri.applyMatch {clip?, referenceTime|Frame|Timecode, faceDetection} sets the grade in one
  undo step and reports the statistics distance before/after; refuses a reference inside the
  clip itself
- Lumetri panel: Color Match row (reference timecode, Face Detection, Apply Match; automation
  ids lumetri.match.*)
- tests: Oklab reference values, self-match is a no-op, a known grade is recovered (residual
  −86 %), skin protection holds the skin hue shift to ≤ 8° (51° without), engine and headless
  UI tests
- docs: control protocol (colour commands and ids), testing; ROADMAP M8 row and log

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:02:54 -04:00
Brandon ThomasandClaude Opus 5.5 42db69edd6 M4.6: playback benchmark results in docs/testing.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:02:47 -04:00
Brandon ThomasandClaude Opus 5.5 995621ff67 M7.4: Essential Sound panel — Browse/Edit tabs, type buttons, collapsible sections with switches and sliders, presets, Clip Volume/Mute footer; docs
- crates/ui-egui/src/panels/essential_sound.rs: per-type sections (Loudness with Auto-Match,
  Repair, Clarity, Creative, Ducking with Generate Keyframes, Duration note, Pan), preset dropdown
  with save/delete, code-drawn type glyphs, automation ids for every control; every control runs an
  essentialSound.* command and a slider drag is one undo step
- headless kittest test (essential_sound_ui.rs) with optional wgpu snapshots
- docs: architecture §5.2, control-protocol ids, testing, ROADMAP

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:40:20 -04:00
Brandon ThomasandClaude Opus 5.5 4b83e088eb Merge main into the playback branch (mixer recordStart moves to the end of preroll; GopCache keeps main's random-access key walk-back)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:30:04 -04:00
Brandon ThomasandClaude Opus 5.5 e7bb3c431c docs: audio mixer (architecture §5.1, control protocol ids, mixer tests); ROADMAP: M7 mixing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 02:12:54 -04:00
Brandon ThomasandClaude Opus 5.5 5170376dcb M4.6: headless playback benchmark (cargo xtask bench-playback) and a correct dropped-frame count
- crates/ui-egui/examples/bench_playback.rs drives the Program monitor's own FrameServer,
  prefetch (now FrameServer::schedule_playback, shared with the monitor) and PlaybackMeter at a
  simulated 60 Hz display, optionally compositing on a headless wgpu device. Scenarios:
  h264-1080, stack3 (3 × 1080p, scaled/rotated/opacity), h264-2160, demo, after-preview
  (live play → Render Effects In to Out → 2 plays), seek-storm. Reports latency percentiles,
  on-time ratio, worker/decode wall and thread-CPU time, UI-thread present time, process CPU per
  frame, decoder seeks/samples (codecs::gop_stats) and wasted jobs; --json for machine output.
  Fixtures are generated with ffmpeg into target/fixtures/playback.
- FrameServer records per-job timings (thread CPU via rustix clocks) while profiling is on.
- Dropped/shown were counted per UI refresh: "shown" counted every refresh that had the frame
  (322 "shown" in an 8 s play of 192 frames) and "dropped" counted a frame that arrived a few ms
  after its first refresh. PlaybackMeter counts timeline frames: shown when the exact picture was
  on screen while due, dropped otherwise, including frames passed over without a refresh.

Baseline (GPU path, 8 s, load avg 104–168 on 14 cores; CPU columns are load-robust):
  h264-1080 Full 191/1 shown/dropped, 46 ms CPU/frame; Half 188/4
  stack3 Full 189/3, 102 ms CPU/frame; Half 157/35 (3 extra decoder seeks)
  h264-2160 Full 8/184, 313 ms CPU/frame, 10 seeks; demo Full 114/78, Half 191/1
  after-preview: live 0/192; 1st play after render 124/67, 2nd 119/73 (UI-thread present
  p50 21 ms / p95 45 ms); seek-storm: 0 of 40 seeks shown within 150 ms

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:44:23 -04:00
Brandon ThomasandClaude Opus 5.5 7dcdef6974 T5: headless scripted UI tests (egui_kittest + control channel)
crates/ui-egui/tests/scripted.rs runs the real FilmcraftApp under
egui_kittest's eframe harness (no window/GPU) and drives it through
ControlRequests, stepping frames until each reply arrives; synthetic
ui.click input is fed through the app's raw_input_hook. Tests: demo
project + widget registry, razor/undo/redo with timeline locate,
source insert, apply Gaussian Blur and see it in Effect Controls,
playback toggle/stop, click a tool button by automation id, error
replies. docs/testing.md documents coverage and limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:39:14 -04:00
Brandon ThomasandClaude Opus 5.5 8eb8f5ff68 T4: BS.1770 loudness oracle test against ffmpeg ebur128
Seven generated signals (sine, pink noise at 48/96 kHz, speech-like at
48/44.1 kHz, gated stereo with silence and sub-gate passages, fs/4
inter-sample peak) written as float WAV and measured by LoudnessMeter
and ffmpeg ebur128 (metadata, 3 decimals per 100 ms). Tolerances: M/S
+-0.1 LU every 100 ms, I +-0.1 LU, LRA +-0.5 LU, true peak +-0.2 dB.
Measured: M/S <= 0.0005, I <= 0.007, LRA <= 0.04 LU, TP <= 0.045 dB.
On the fs/4 tone ffmpeg's true peak is +0.6 dB above the analytic
value, so that case is checked against the analytic peak (ours -0.053).
testkit gains a float WAV writer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:32:25 -04:00
Brandon ThomasandClaude Opus 5.5 7655447233 T3: golden-image tests for the renderer + GPU parity; fix stale GPU uploads
crates/golden (test-only, L3): nine procedural 320x180 scenes (transform
and opacity, blend modes, Gaussian Blur, Lumetri basic, Crop, Cross
Dissolve / Dip to Black / Wipe mid-transition, timecode/clip-name text)
rendered on the CPU and compared with committed goldens (PSNR >= 45 dB,
max <= 12, p99 <= 2); FILMCRAFT_BLESS=1 regenerates them with
attribution sidecars. testkit::golden adds PNG I/O, diff metrics and
failure images. The same scenes are composited on the GPU and compared
with the CPU.

GPU parity exposed a real bug: GpuCompositor cached uploads by
pixel-buffer address without owning the buffer, so a new frame
allocated at a freed frame's address was drawn with a stale texture
(whole wrong frames, PSNR ~12 dB). The cache now keeps the buffer
alive; regression test upload_cache_keeps_buffers_alive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:26:14 -04:00
Brandon ThomasandClaude Opus 5.5 3704002f89 T2: cargo xtask fixtures pre-generates the oracle fixture matrix
Runs each crate's ignored generate_fixtures test (h264, hevc, isobmff,
matroska, prores) - the same generators the oracle tests use - and
prints made/cached/skipped per fixture plus a summary. Optional crate
filter: cargo xtask fixtures hevc prores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:20:59 -04:00
Brandon ThomasandClaude Opus 5.5 8780d5ffa2 T1: shared ffmpeg/ffprobe discovery in filmcraft-testkit
New dev-dependency-only crate crates/testkit (L0, no FilmCraft deps):
FILMCRAFT_FFMPEG/FILMCRAFT_FFPROBE, then PATH (incl. .exe), then known
dirs; SKIPPED lines and FILMCRAFT_REQUIRE_ORACLES=1 to make skips fail;
require_ffmpeg!/require_ffprobe!/require_oracles!; fixtures_dir() under
<workspace>/target/fixtures with per-thread temp names and atomic
generation. Oracle helpers in aac, opus, h264, hevc, h264enc, isobmff,
matroska, prores and export migrated (codecs left on its local lookup).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:10:59 -04:00
Brandon ThomasandClaude Opus 5.5 4e2a8077d1 docs: public architecture, contributing, testing and agent guides
Public equivalents of the maintainer-local plan/: docs/architecture.md (layers as enforced by
xtask, Tick time base, data model, command system and undo, render/playback/export pipeline,
automation surfaces), docs/contributing.md (+ root CONTRIBUTING.md), docs/testing.md and
docs/agents.md (MCP/control channel usage, agent work loop, decision rules, Definition of Done).
CLAUDE.md points at the public docs wherever it references plan/; AGENTS.md gains a See also list;
README gains a Documentation section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:24:13 -04:00