Commit Graph

189 Commits

Author SHA1 Message Date
Brandon Thomas 7c21ec5e13 Merge main into #1068 (engine dev-dependencies, docs)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:55:08 -04:00
Brandon Thomas f704b46906 Merge pull request #1064 from MrCloudy2/feat/vp8-decoder-432
#432: VP8 video decodes (clean-room pure-Rust VP8 decoder), so VP8 WebM no longer shows black
2026-10-11 21:02:52 -04:00
Brandon Thomas 5ce44e2bd8 Merge pull request #650 from JordyUSA/feat/598-avi-import
#598: import AVI files (clean-room AVI / OpenDML demuxer)
2026-10-11 21:02:51 -04:00
Brandon Thomas 8ec1a36b9f Merge pull request #613 from JordyUSA/feat/flac-export
Export: FLAC (clean-room encoder; .flac files and FLAC audio in MP4/MOV)
2026-10-11 21:02:50 -04:00
Brandon Thomas 06e5ac6651 Merge pull request #819 from vangel76/gap-mp2-decoder
#809: own MPEG audio Layer I / II decoder plays MP2 at ffmpeg's default bit rates
2026-10-11 21:02:50 -04:00
Brandon Thomas 47b0688483 Merge main into #650; AVI frames pass an unspecified transfer to vui_color
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:02:34 -04:00
Brandon Thomas c7f6eccb18 Merge remote-tracking branch 'origin/main' into fix-650 2026-10-11 21:00:53 -04:00
Brandon Thomas 22d069560a Merge pull request #843 from vangel76/gap-workflow-acceptance
#835: workflow acceptance tests through the MCP server, checked by ffprobe
2026-10-11 20:32:42 -04:00
Brandon Thomas dab9630d68 Merge pull request #846 from MrCloudy2/fix/export-hevc-stall-480-v2
#480: exports no longer stop for good when a clip's decoding uses rayon (rotated iPhone HEVC clips)
2026-10-11 20:29:56 -04:00
Brandon Thomas 6b860ede89 Merge main into #1140 (docs/gaps.md)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:34:14 -04:00
Brandon Thomas 1661344ba6 Merge pull request #891 from vbasky/fix/823-multi-audio-import
Import every MPEG audio stream, not only the first PID
2026-10-11 19:18:35 -04:00
seif cfe0c751e9 #395: Arabic and Hebrew in the interface: fallback fonts, captions in reading order
The interface had no face for Arabic or Hebrew, so caption text, track and media names showed
missing-glyph boxes in the Text panel and on the timeline while the Program monitor drew them.
crates/ui-egui/src/rtl.rs adds the craft-fonts Arab / Hebr faces, else one installed face per
script (Noto Sans Arabic, SF Arabic, Segoe UI...), as the last fallbacks of every UI font family,
as cjk.rs does for Chinese.

egui already shapes each font run with harfrust, so the letters join, but it lays runs out left to
right with no bidi pass and multi-word Arabic read backwards. rtl::Lines lays captions out in
reading order: lines are broken on the logical text as egui wraps it, each line is reordered with
unicode-bidi (UAX #9, as crates/text does for titles) and every right-to-left word is its own
layout section for egui's shaper. Caption blocks on the timeline and the Text panel caption list
use it; a caption being edited keeps egui's logical order, since TextEdit places the caret by
character index. Left-to-right text is laid out exactly as before.
2026-10-11 13:14:30 -06:00
vangel76 28247afae7 #1065: clean-room DNG / CinemaDNG decoder crate
Problem: camera RAW is at 0% (docs/codec-parity.md, #383). CinemaDNG,
the one cinema RAW format with a public specification, could not be
read at all.

Fix: new L0 crate filmcraft-dng, written from the public DNG 1.4-1.7,
TIFF 6.0 / TIFF-EP, ITU-T T.81 and CinemaDNG specifications only (no
other decoder's source read; editions in the crate README):
- TIFF container with SubIFDs, bounded (64 IFDs, 4 levels, cycles end
  the walk) and checked offsets; the main raw IFD is the largest
  NewSubFileType 0 CFA / LinearRaw image.
- Raw data: 1-16-bit uncompressed (MSB-first packing) and lossless JPEG
  (process 14, predictors 1-7, 1-4 components, point transform, line
  restarts), strips and tiles, tiles decoded in parallel; allocations
  capped by size and by the data present.
- Processing per the DNG model: ActiveArea, LinearizationTable, per-site
  black levels with deltas, white levels, as-shot white balance with
  neutral highlight clipping, Malvar-He-Cutler Bayer demosaic (bilinear
  for other patterns), DefaultCrop, ColorMatrix / CameraCalibration /
  ForwardMatrix with illuminant interpolation, Bradford to linear
  Rec. 709, BaselineExposure; output scene-linear RGBA floats.
- CinemaDNG FrameRate, TimeCodes and ReelName tags.
- A test-only writer (feature `writer`) synthesises DNGs. Tests: raw
  samples bit-exact for every depth / predictor / layout, processing
  against hand-computed values, hostile files (every truncation, 12k
  mutations, cyclic IFDs, huge sizes, bad offsets), and LibRaw's
  unprocessed_raw as an external oracle reading the same samples
  (skipped when not installed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:44:00 +02:00
MrCloudy2 53a0d959fe #432: VP8 video decodes (clean-room pure-Rust VP8 decoder)
VP8 WebM showed black video: there was no VP8 decoder. New L0 crate
filmcraft-vp8, implemented from RFC 6386 sections 1-19 (tables extracted
from the RFC text, nothing from the attached reference decoder): every
coding tool, versions 0-3, hidden altref frames, size changes. Bit-exact
with libvpx on 62 libvpx VP8 test vectors, real-world FATE samples and
generated fixtures; never panics on corrupted input.

Wired into codecs for Matroska / WebM (V_VP8, including the alpha layer
of transparent WebM) and MP4 (vp08). VP8 colour is BT.601 (RFC 6386 9.2).
A hidden altref frame is a WebM block of its own with the time of the
frame that follows it: the VP8 time lookup now moves on to that shown
frame instead of repeating the previous one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:13:07 +02:00
vangel76 fc3b7ae9fc Merge remote-tracking branch 'upstream/main' into gap-mp2-decoder 2026-10-11 08:53:44 +02:00
vangel76 00ad651814 Merge upstream/main into gap-gpu-safe-start
Conflict in apps/filmcraft/src/main.rs: kept the graphics start loop and
app_creator, and carried over --control-input-only (#881) into them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:47:25 +02:00
JordyUSA 773e1a3c72 Merge origin/main into feat/flac-export
Keep FLAC beside main's new AAC Audio format (21 formats, both audio-only
presets), use is_mp4_with / is_mp4_video in audio_codec() and the Audio
Format picker so MP4 (incl. AV1) offers AAC or FLAC, and add flacLevel to
main's export.media params.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:32:13 +07:00
Vikram Bhaskaran f733230b9f
#823: import every MPEG audio stream, not only the first PID
Transport and program streams listed a single audio stream, so file.import
and New Sequence From Clip kept one clip. Probe every audio PID (capped),
decode each independently, and place linked clips per stream. MP4/MKV
already did this; MXF same-rate PCM is still interleaved as one stream.
2026-10-11 13:01:20 +11:00
vangel76 482783e538 #809: Cargo.lock picks up the 0.6.0 workspace version for filmcraft-mpa
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 03:00:46 +02:00
vangel76 b74202696d Merge remote-tracking branch 'upstream/main' into HEAD 2026-10-11 03:00:38 +02:00
skylar taylor-barrick 1996723225 UI.6: refresh shared UI integration against current main 2026-10-10 18:51:04 -06:00
Brandon Thomas 2ff3f5e266
Release prep: 0.6.0 and a Linux riscv64 release build (#830)
- release.yml: new `linux-riscv64` job, cross-compiled on ubuntu-24.04 against
  ports.ubuntu.com riscv64 libs (ported from GridCraft), tar.gz only, CLI
  smoke-tested under QEMU. Installs libasound2-dev:riscv64 for cpal/ALSA; the
  VA-API and NVDEC/NVENC paths are loaded with libloading at run time, so they
  need no riscv64 libraries. The draft-release job now needs it, so its tarball
  is uploaded and covered by SHA256SUMS.txt.
- packaging/linux/package.sh: CROSS_ARCH / CROSS_TARGET / CROSS_COMPILE /
  EMULATOR support, as in GridCraft.
- README and docs/releasing.md list the riscv64 tarball.
- cargo xtask version set 0.6.0 (Cargo.toml, Cargo.lock); refresh contributors.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:28:41 -04:00
vangel76 fc855e2b0e #835: workflow acceptance tests through the MCP server, checked by ffprobe
Problem: no test did a real editing job end to end. Codec and container
oracles exist, but nothing imported phone- or camera-like media, edited
it through the command layer and checked the exported file (G6).

Fix: apps/filmcraft-cli/tests/workflows.rs drives the `filmcraft-cli mcp`
binary over stdio on media generated with ffmpeg into target/fixtures:
- a VFR H.264 + AAC MP4: sequence from clip, extract, -6 dB audio gain,
  title, H.264 MP4 export;
- a long-GOP H.264 MKV with AAC + AC-3 tracks: ripple trims, colour matte,
  centred cross dissolve, save; a new CLI process exports ProRes.
ffprobe / ffmpeg check streams, frame count, duration, which source frame
lands where, A/V sync across the cut, title pixels, the dissolve mix and
audio levels. The tests skip without ffmpeg (testkit oracles).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:26:42 +02:00
MrCloudy2 f79a51dd24 #480: exports no longer stop for good when a clip's decoding uses rayon
A GopCache decodes with its lock held, and that decoding starts rayon work
(rotating iPhone frames, cropping, slice-threaded decoders). On the global pool
a worker that took part of it could, waiting inside it, pick up another render
job asking the same cache for a frame and block on the lock, while the lock
holder waited for the work on that worker's stack: exports of rotated iPhone
HEVC clips stopped making frames in about half the runs.

The locked decoding now runs on a separate decode pool, whose threads never wait
for a cache's lock; a caller that is a rayon worker waits on a plain thread so it
does no other rayon work while holding the lock. The cancel/catch-up/draft/
background hints travel with it (filmcraft_media::cancel::Context). Intra-only
streams crop and rotate before taking the lock again.

Second version of #662 (reverted): the regression test's stand-in decoder summed
with overflow, which panics in debug builds; it now wraps explicitly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:16:43 +02:00
vangel76 116364cf08 #820: fall back to DX12, then a software adapter, when the graphics start fails
Problem: a graphics driver that crashes inside wgpu instance or device
creation (Intel Vulkan igvk64.dll #512 #413 #793, AMD atio6axx.dll #477)
killed every launch the same way until the user set WGPU_BACKEND by hand;
a start-up error wgpu did report ended in an error dialog.

Fix: each start leaves a marker in the data folder (graphics-start.json),
cleared once the window has painted two frames. A marker still pending at
the next launch moves on along the platform's ladder (Windows: Vulkan+DX12,
DX12 only, software/WARP; Linux: default, software/lavapipe or llvmpipe)
and keeps the mode that works. A wgpu start-up error moves on within the
same process (eframe reuses its event loop). Fallback modes don't register
the GPU export renderer, whose own instance would load the failed driver.
An explicit WGPU_BACKEND leaves the marker alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:58:45 +02:00
vangel76 39afd2f6c3 #809: own MPEG audio Layer I / II decoder plays MP2 at ffmpeg's default bit rates
Problem: symphonia rejects every Layer II frame whose bit rate / mode
combination ISO/IEC 11172-3 does not allow (mono above 192 kbit/s, stereo
below 64 kbit/s). ffmpeg writes mono MP2 at 384 kbit/s by default, so such
tracks played as silence in MPEG-TS / PS, Matroska and raw .mp2 files.

Fix: new L0 crate filmcraft-mpa, a clean-room Layer I / II decoder written
from ISO/IEC 11172-3 and 13818-3 (all modes incl. joint stereo, MPEG-1/2/2.5
rates, the disallowed combinations decoded with the allocation table their
bit rate per channel selects). PacketDecoder::mpeg_audio uses it for layers
I and II (packets of several frames too); raw .mp2 files decode with it,
resyncing after damage. Oracle tests vs ffmpeg: 73-84 dB SNR on ffmpeg /
twolame streams and synthetic Layer I / joint stereo frames; fuzzed damaged
frames never panic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:48:45 +02:00
skylar taylor-barrick baadac2cf8 UI.9: integrate shared docking and preserve workspace behavior 2026-10-10 14:59:52 -06:00
Brandon Thomas 9a13e7c8f3
Merge pull request #657 from vangel76/fix-642-open-links
#642: open Help/About links in the system browser on the desktop
2026-10-10 15:51:56 -04:00
Brandon Thomas e78223db6d Revert "Merge pull request #662 from MrCloudy2/fix/export-hevc-stall-480"
This reverts commit aa8ad402cc, reversing
changes made to 5f9b5e1234.
2026-10-10 15:24:44 -04:00
vangel76 15bf7f9f48 Merge remote-tracking branch 'upstream/main' into fix-642-open-links
# Conflicts:
#	apps/filmcraft/src/main.rs
2026-10-10 20:57:56 +02:00
Brandon Thomas aa8ad402cc
Merge pull request #662 from MrCloudy2/fix/export-hevc-stall-480
#480: exports no longer stop for good when a clip's decoding uses rayon (rotated iPhone HEVC clips)
2026-10-10 14:53:51 -04:00
Brandon Thomas 1879a30db8
Merge pull request #615 from ReReddo/feat/clipboard-paste
timeline, project panel: paste images and copied files from the system clipboard
2026-10-10 14:53:02 -04:00
MrCloudy2 69bb1dd33c #480: exports no longer stop for good when a clip's decoding uses rayon
A GopCache decodes with its lock held, and that decoding starts rayon work
(rotating iPhone frames, cropping, slice-threaded decoders). On the global pool
a worker that took part of it could, waiting inside it, pick up another render
job asking the same cache for a frame and block on the lock, while the lock
holder waited for the work on that worker's stack: exports of rotated iPhone
HEVC clips stopped making frames in about half the runs.

The locked decoding now runs on a separate decode pool, whose threads never wait
for a cache's lock; a caller that is a rayon worker waits on a plain thread so it
does no other rayon work while holding the lock. The cancel/catch-up/draft/
background hints travel with it (filmcraft_media::cancel::Context). Intra-only
streams crop and rotate before taking the lock again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:14:34 +02:00
vangel76 b24225afd3 #642: open Help/About links in the system browser on the desktop
Problem: every link (Help menu, About dialog, header Discord button, Import
screen, Settings and Keyboard help) went through egui's `ctx.open_url`. The
workspace builds eframe without its `links` feature, so egui-winit only logs
"Cannot open url - feature links not enabled" and nothing opens on Linux,
Windows or macOS.

Fix: add a `HostHooks::open_url` hook, as PhotoCraft does. `links::open` now
takes the app and calls the hook, falling back to `ctx.open_url` when it is
unset or fails (the web build keeps opening a new tab). The desktop app sets
it to `open::that_detached` (open 5, MIT), which does not block the UI
thread. Test: every Help link reaches the hook, and a failing hook falls
back to `ctx.open_url`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:58:26 +02:00
JordyUSA 8ea94a8541 Merge main into feat/flac-export
No conflicts. main's new Chinese catalog requires every tl! string:
added zh-CN for the FLAC labels (format, preset, Audio Format entry,
Compression Level and its hint).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:53:52 +07:00
JordyUSA 2f4b59329e #598: filmcraft-avi, a clean-room AVI / OpenDML demuxer
New L0 crate written from the AVI RIFF file reference and OpenDML 1.02:
avih and per-stream strh / strf (BITMAPINFOHEADER, WAVEFORMATEX(TENSIBLE))
/ strn, and chunk tables from the best index a file has: the OpenDML indx
super index and ix## standard indexes (field indexes too), else idx1
(offsets relative to movi or absolute) plus a scan of RIFF AVIX
extensions it cannot see, else a scan of the movi lists (key frames then
unknown). Frames are read on demand through a ByteSource.

Sizes are clamped to the file, so a cut-off recording opens with what
is there; rec lists nest at most 3 deep and tables are bounded by what
the file could hold. Tests: hand-built files for every index path,
truncation, and every single-byte mutation and truncation (no panic);
ffmpeg-made files against ffprobe; an ignored test on a 1.16 GB OpenDML
file with AVIX extensions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:21:30 +07:00
ReReddo 06b835d5a8 timeline, project panel: paste images and copied files from the system clipboard (#611)
Ctrl+V with a screenshot or an image copied in another app, or with files
copied in Explorer / Finder, now pastes them. In the Timeline they are
imported and placed at the playhead, end to end, without overwriting
anything: each clip goes on the first free track from the targeted one
outward (up for video, down for audio), and a track is added when every
track is busy there. Ctrl+Shift+V inserts them on the targeted tracks, as
Paste Insert does. In the Project panel Ctrl+V imports into the shown bin.
One undo step takes the paste back.

Copying clips already puts their names on the system clipboard as text, so
media on the clipboard was copied after them; without media, Paste pastes
the copied clips as before.

- engine: edit.pasteMedia {paths, insert, place, bin}; paste_media::
  save_pasted_image writes "Pasted Image <n>.png" where voice-over takes and
  narrations go (voiceover::media_dir: Scratch Disks > Captured Audio and
  Video, else next to the project, else the data directory), trying a
  bounded number of names as voiceover::unique_wav_path does.
  timeline.place's default length moves to commands::full_duration so both
  share it.
- ui-egui: HostHooks::clipboard_media reads the clipboard (ui-egui stays
  OS-independent); menus::invoke turns edit.paste / edit.pasteInsert into a
  media paste when the Timeline or Project panel has focus. egui-winit drops
  the Ctrl+V press when the clipboard holds no text but passes the release,
  so a V release without its press puts the press back. That also makes
  Ctrl+V paste copied clips when the system clipboard is empty.
- filmcraft (desktop): the hook, with arboard (already in the tree through
  egui): copied files first, else an image.

Not covered: the web build, whose browser clipboard works differently.

Tests: paste_media_tests (5: image above the footage with nothing
overwritten and one undo step, tracks added when every track is busy,
Paste Insert, import only, saved image names) and clipboard_paste_ui (4:
an image pasted from a key release with no text, copied files and Paste
Insert, the Project panel imports, copied clips still paste and a plain V
pastes nothing).
2026-10-10 15:34:47 +03:00
Brandon Thomas 58f768c472 Merge origin/main into gpu-rendering
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:27:57 -04:00
Brandon Thomas c030f78762 Merge origin/main into tts-narration
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:13:05 -04:00
Brandon Thomas 7f81d6b063
Merge pull request #390 from txiki739/fix/linux-file-dialog-extensions
#262: file dialogs list extensions in any capitalisation on Linux
2026-10-10 08:09:51 -04:00
JordyUSA 055e95ab17 Export: FLAC (clean-room encoder; .flac files and FLAC audio in MP4/MOV)
New L0 crate filmcraft-flac, a FLAC encoder written from RFC 9639:
constant / verbatim / fixed / LPC subframes (Levinson-Durbin on Tukey-
windowed autocorrelation, up to order 12), partitioned Rice residuals,
left/side, side/right and mid/side stereo, CRC-8/CRC-16, STREAMINFO with
MD5 (RFC 1321, own implementation), levels 0-8, all lossless.

Export:
- Format::Flac, an audio-only .flac (16/24-bit), streamed one second at
  a time like WAV/AIFF; STREAMINFO is rewritten at the end with frame
  sizes, total samples and MD5. Preset "FLAC 48 kHz 24-bit".
- AudioCodec::Flac in MP4 and QuickTime (fLaC + dfLa), one frame per
  sample with the short last frame timed exactly; the dfLa STREAMINFO
  is replaced before the moov is written (Mp4Writer::set_sample_entry).
  MXF stays PCM.
- AudioSettings::flac_level (default 5); Export panel: FLAC (lossless)
  audio format and Compression Level; file.exportMedia `format: "flac"`,
  `audioCodec`, `flacLevel`. Spanish and Japanese strings.

ffmpeg oracle: every stream decodes bit-exactly with the STREAMINFO MD5
equal to ffmpeg's hash; .flac and FLAC-in-MP4/MOV exports decode to the
same samples as a WAV export of the range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:26:28 +07:00
Brandon Thomas c9e803ff3b Merge origin/main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:24:39 -04:00
Brandon Thomas 762344769b Merge origin/main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:21:39 -04:00
Brandon Thomas 4304cd9382 Merge origin/main into #421; GPU export opt-in, wgpu error handler, drop panicked renderers
- GpuRendering defaults to Off (opt-in per export) until measured on Windows and macOS;
  docs and ROADMAP say so.
- The shared export device installs an uncaptured-error handler and a device-lost callback
  that log once and retire GPU export for the session (frames go to the CPU) instead of
  wgpu's default panic.
- RendererPool drops a renderer that panicked and retires the pool, so the rest of the
  export renders on the CPU (regression test in gpu_hook_scenarios); the duplicate
  hostile-size test that raced on the global registry is folded into it.
- Rebased onto main's render_plan/transitions: render_export_prepared reads the linear
  accumulator after render_plan; transition (Composite) plans fall back to the CPU.
- es/ja rows for the new Export strings; web_time::Instant in the export pipeline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:21:38 -04:00
Brandon Thomas 664c13efeb Merge origin/main into #278; schema v14, neural-voices off by default, review fixes
- Narrations take schema v14 (main's v13 is audio streams): v13_to_v14, docs updated.
- neural-voices is off by default in the desktop app, like whisper; the model download stays
  an explicit, confirmed job.
- Removed the debug probe2 test module from tts-text.
- project_subset prunes narrations of items it drops.
- unique_wav_path is bounded (99 999 names) and returns an error instead of looping.
- narration.rs uses web_time::Instant (wasm clock test); tts.* commands get the
  "Text to Speech" shortcut category, with es/ja rows for it and Edit Narration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 06:55:59 -04:00
Brandon Thomas 634d6cf359 Merge origin/main into #390; case-insensitive filters on main's translated dialog labels
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 05:46:50 -04:00
Luniiya 9e3c9c9b65 Merge remote-tracking branch 'upstream/main' into feat/system-appearance
# Conflicts:
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/icons.rs
2026-10-10 11:32:04 +02:00
Brandon Thomas 7bd7621262 Bump version to 0.5.0 (from 0.4.0) for release; refresh contributors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:02:11 -04:00
Luniiya 77fa159f49 ui: standardise system appearance modes and theme previews 2026-10-10 02:14:55 +02:00
Brandon Thomas bb4c6d0bb2 Format: repair out-of-range audio stream data on load instead of refusing the project
A clip with audio_stream >= MAX_AUDIO_STREAMS is reset to stream 0 and media
with more than MAX_AUDIO_STREAMS streams keeps the first ones, each with a
warning: one bad index must never lose a whole project.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:08:10 -04:00