Commit Graph
4408 Commits
Author SHA1 Message Date
vangel76 6dcaea2ac6 #3300: read_aepx keeps its own owned-tree reader
read_aepx, read_aepx_with_limits and parse_any build the owned chunk
tree element by element again, as before the .aepx index, instead of
converting the index (which held the decoded buffer and the owned tree
at the same time). Import keeps the index reader. The tests now
compare the two production readers.
2026-11-08 18:49:19 +01:00
vangel76 3a9cb48259 Merge remote-tracking branch 'upstream/main' into aep-audit-3300 2026-11-08 18:29:49 +01:00
vangel76 a33fb4abf6 #3300: import .aepx through the flat index
The .aepx reader no longer builds the owned chunk tree element by
element. It decodes every body (hex, text, alias JSON, numbers) into
one buffer and records the chunks as depth-first entries whose bodies
are ranges of that buffer; TreeIndex::from_drafts turns them into the
index the importer reads, which borrows the buffer. read_aepx converts
that index into the owned tree in one pass.

The tree and the errors are those of the previous reader, which the
tests keep as the reference: generated and damaged documents under
seven limit sets, invalid UTF-8, hostile input, the fixture directory,
and imports through both. Bound tests pin the chunk list to the input
and the limit, and check that dropped content leaves nothing behind.
2026-11-08 18:19:12 +01:00
FredApps a41ff5015c Merge pull request #3129 from vangel76/aep-import-lumetri
.aep import: map Lumetri Color
2026-11-08 17:19:43 +01:00
FredApps 86c08aa0ee Keep native control renders responsive (#3306)
* Keep native control renders responsive

* Refresh replies for immediately completed render jobs

* #3289: Bind waiting replies to their native render
2026-11-08 16:43:06 +01:00
vangel76 5f2d88ea5c Merge remote-tracking branch 'upstream/main' into aep-import-lumetri
# Conflicts:
#	crates/aep/src/container/effect_map.rs
#	crates/aep/src/export/effects.rs
#	crates/aep/src/import/effects.rs
#	crates/aep/tests/it/export/effects.rs
#	crates/aep/tests/it/import/effects.rs
#	docs/aep-import.md
2026-11-08 16:32:43 +01:00
vangel76 5f4e7ffc18 Merge remote-tracking branch 'upstream/main' into aep-audit-3300 2026-11-08 16:21:58 +01:00
vangel76 2e24ae47a1 aep export: the time remap and Transform keys use the shared key-list and match-name helpers; doc comments for the audit's functions (#3300) 2026-11-08 16:21:57 +01:00
FredApps 07be19d402 Merge pull request #3255 from vangel76/aep-import-puppet-3093
AEP import: Puppet arrives as EffectCraft's Puppet, its meshes and pins are reported
2026-11-08 15:46:00 +01:00
FredApps 7ca249d085 Merge pull request #3120 from vangel76/aep-import-thirdparty
.aep import: map CC Color Neutralizer, EXtractoR and IDentifier
2026-11-08 15:45:08 +01:00
FredApps 5832219d76 Merge pull request #3248 from vangel76/text-layer-name-follow-3233
Text layers: the name follows the text until the user renames the layer
2026-11-08 15:44:58 +01:00
FredApps 362b39038f Merge pull request #3256 from vangel76/clamp-time-stretch-3247
Time stretch: hold a loaded or imported stretch to ±1 % to ±9900 %
2026-11-08 15:44:45 +01:00
vangel76 b80ac9edb9 aep: read imports through a flat tree index (#3300)
Import reads an .aep through TreeIndex, one depth-first array of chunks that
borrows the file's bytes, instead of building and freeing the owned Chunk tree
(one Vec per list). The parser mirrors read::Parser step for step: the same
chunk count order against max_chunks, the same depth limit and opaque
fallbacks, the same errors. The typed view reads through Node, a handle to a
chunk of either tree, so the accessors work unchanged on both; .aepx keeps its
owned tree. Chunk, parse and write stay for export and editing.

The array starts small and doubles, never past what the input can hold or the
chunk limit allows; a failed allocation is TooLarge, a tree past u32 indices
TooManyChunks.
2026-11-08 15:00:52 +01:00
vangel76 d2ca544404 Merge remote-tracking branch 'origin/aep-cleanup-3281' into aep-audit-3300 2026-11-08 14:23:06 +01:00
vangel76 a7456fac62 Merge remote-tracking branch 'origin/aep-export-dedup-3278' into aep-audit-3300 2026-11-08 14:23:06 +01:00
vangel76 47d988f658 Merge remote-tracking branch 'origin/aep-export-template-3277' into aep-audit-3300 2026-11-08 14:23:06 +01:00
vangel76 2428b8091e Merge remote-tracking branch 'origin/aep-textdoc-3276' into aep-tree-index-3300 2026-11-08 14:15:51 +01:00
vangel76 c862ce0aa0 aep: the format notes name the 1 x 1 mask scale of text and shape layers (#3281) 2026-11-08 08:18:44 +01:00
vangel76 b3c89f314c aep: the format notes name the accessors that remain (#3281) 2026-11-08 06:19:18 +01:00
vangel76 d6ec32cbaa aep export: correct the order the natural sort key doc gives for equal numbers (#3277) 2026-11-08 06:19:17 +01:00
vangel76 c8ccf807e1 #3233: AEP import names an unnamed text layer as a following name is cut, so export and import agree 2026-11-08 04:53:01 +01:00
vangel76 e41d6d9d68 Merge remote-tracking branch 'upstream/main' into text-layer-name-follow-3233 2026-11-08 04:42:27 +01:00
vangel76 d2359d607e aep export: the every-layout test counts from a baseline, not from zero (#3278) 2026-11-08 04:41:46 +01:00
vangel76 0643687832 Merge remote-tracking branch 'upstream/main' into aep-container-alloc-3275 2026-11-08 04:36:37 +01:00
vangel76 245e9b6844 aep container: check bdata digits and size before reserving (#3275)
decode_hex reserved the decoded size before it knew the value decodes,
so a large bdata with a bad digit reserved half its length first. It now
refuses a value larger than a chunk's 32-bit size field (TooLarge), checks
every digit in one vectorisable pass, and only then reserves, with
try_reserve_exact so a value that does not fit in memory is an error
instead of an abort.
2026-11-08 04:36:37 +01:00
vangel76 02024d6e32 Merge remote-tracking branch 'upstream/main' into aep-export-template-3277 2026-11-08 04:36:19 +01:00
vangel76 8439daea0b aep export: sort keys as one compact byte string, bounded by the name (#3277)
The cached natural keys were Vecs of (bool, String, u128) segments: a 255-byte
name of alternating letters and digits took about 14 KB, held for every item at
once. Each key is now one byte string whose byte order is the natural order,
at most 5 bytes per name byte. Order and output are unchanged.
2026-11-08 04:36:18 +01:00
vangel76 f5ec122466 aep: drop a local check tool committed by mistake (#3281) 2026-11-08 04:34:49 +01:00
vangel76 66cbb9d89e aep: review fixes for #3281: NTSC table beside TimeBase, real-path NTSC round trip, light and camera defaults on import, doc wording 2026-11-08 04:34:39 +01:00
vangel76 4c1a75aa9e Merge remote-tracking branch 'upstream/main' into aep-cleanup-3281 2026-11-08 04:06:54 +01:00
vangel76 9e2461414a aep: remove test-only container accessors, share report and time-base code (#3281)
- Remove 35 public container accessors that only tests called (header,
  camera/light, keys, footage, masks, shapes, version) and the dead
  StyleMap::switch_name. Tests now check the importer's own reading of the
  same bytes, or the decoder it uses; three import tests gain the values
  the removed checks covered.
- Import and export reports share one loss entry (Loss<C>) with record,
  total, count and summary; the JSON shape is pinned for both.
- Collector::lose_with builds a detail only below the detail cap (callers
  switch later).
- The export uses the container's TimeBase; one NTSC table serves import
  and export; TimeBase::frames saturates like units instead of returning 0.
2026-11-08 04:04:49 +01:00
FredAppsandClaude Opus 5.5 3e0c77ca68 Preview: the sound plays on through stalls, the picture drops frames (#2473) (#3279)
* Preview: the sound plays on through stalls, the picture drops frames (#2473)

A preview whose rendering fell behind stopped its sound at the first frame
that wasn't cached and started it again once frames were cached, which
chopped it into bursts. Now the sound plays on: the picture shows the latest
frame rendered up to the sound, and the prefetch and the cache's eviction
order follow the sound's frame rather than the picture's.

The stall backoff from #3272 no longer has anything to do and is removed.
The start of a preview still waits for its first frames (#947).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Preview: a picture behind its sound never shows past the sound's frame

`latest_cached_before` stopped only on the sound's exact frame, which a
picture off the plan's frame step steps over and a sound behind the picture
in a non-looping preview never reaches, so it could return a frame ahead of
the sound. The walk now stops at the first frame that isn't between the
picture and the sound in play order (across the loop's end once the sound
has wrapped). Also brings `Playback::starting`'s doc up to date.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:03:31 +01:00
vangel76 30a6e571c9 aep: review fixes for #3276 text documents and markers
text_document reads the first btdk in the Source Text record, the documents
text_document_count counts. The old slot checks (same, is_neutral, undecoded_fields)
join the test oracle and are compared on 20 000 generated slot dictionaries; mixed
dictionary/array chains and a document left open at the depth limit join the parser
differential. An escaped string's byte order mark is drained without a copy.
2026-11-08 03:58:10 +01:00
vangel76 9e82a5e704 aep export: review fixes for #3278
- tree::Fixed replaces tree::fixed: a fixed layout writes every field that
  fits (as the old code did) and keeps the first error; finish() logs it
  once with the layout's description and counts it per thread, so the
  every-layout test cannot race with other tests.
- base::bytes logs one line naming its length and fields.
- masks::build_atom errors when the prototype has no Mask Shape instead of
  dropping the path of every mask quietly.
- log sorted into the dependency list.
2026-11-08 03:56:50 +01:00
vangel76 a4f9a97525 aep export: pin the key-time loop's report, name the layout in the base::bytes log (#3278) 2026-11-08 03:43:04 +01:00
vangel76 501e1bd4bf Merge commit 'ae35ea7d' into aep-export-dedup-3278 2026-11-08 03:43:03 +01:00
vangel76 5f37f78117 aep export: one key-time loop, key-list rewrite, tdmn decoder and byte writer for the listed modules (#3278)
In masks, shapes, styles, synth, fxsynth, base, camlight, skeleton,
textanim and tree (effects.rs, plan.rs and emit.rs keep their copies for
the follow-up work):
- New export/keys.rs: the key-time loop (timed_keys), the key-list rewrite
  (fill_key_list, set_key_list, replace_cdat) and the spatial key record,
  shared by masks, shapes and styles.
- One tdmn decoder (synth::tdmn_name, lossy UTF-8 up to the first NUL, as the
  importer reads it) and one encoder (synth::tdmn) instead of the copies in
  masks, styles, shapes, textanim, camlight and skeleton.
- One byte writer: tree::put, which errors. base::bytes, synth::tdb4,
  synth::key_list, fxsynth::pard, masks::shph and the keyed path records write
  through it; their fixed layouts keep the infallible signatures behind
  tree::fixed, which logs, and a test builds every layout and requires no error.
- camlight::put_group uses the shared group split (tree::split_group), which
  errors on a match name without a node instead of stopping quietly.

Export output is byte-identical on the corpus and the synthetic fixtures.
2026-11-08 03:43:01 +01:00
vangel76 6c84c81060 aep: an escaped text string drops its byte order mark without a range drain (#3276) 2026-11-08 03:42:48 +01:00
vangel76 34715bbd86 aep: text-dict test builds its prefix without repeat(1) (#3276) 2026-11-08 03:37:19 +01:00
vangel76 ff5952ee5d Merge remote-tracking branch 'upstream/main' into aep-textdoc-3276 2026-11-08 03:29:45 +01:00
vangel76 32c79babc8 aep: text documents are read without a String per token, defaults built once (#3276)
TextDocument::parse reads a borrowed tree: names, bare words and strings without
escapes point into the body, keys are borrowed when they are /names, numbers parse from
the borrowed bytes, and dictionaries and arrays are moved into vectors of their exact size
when they close. The style and paragraph defaults are built once instead of per document.
parse_text_dict keeps its public TextValue result (the borrowed tree turned owned).

The old owning parser stays as a test-only oracle: a differential test compares both on
40 000 generated bodies (every key form the owned keys canonicalise, non-UTF-8 names,
escapes, unclosed strings, non-finite numbers), every cut of a realistic document and
nesting around the depth limit.
2026-11-08 03:27:12 +01:00
vangel76 cdb81c06ec aep export: note what the concurrency test covers and why a failed template build is not kept (#3277) 2026-11-08 03:26:16 +01:00
vangel76 efa0c94d2b aep container: review fixes (#3275)
- read.rs: reserve with try_reserve_exact, so a raised chunk limit on a
  small target cannot abort before parsing; the capped reservation and a
  deep, retry-heavy nest of broken lists are pinned by tests.
- write.rs: a tree past the 32-bit container size fails with TooLarge
  before anything is serialised.
- aepx.rs: drop an unneeded local and lifetime annotation.
2026-11-08 03:24:05 +01:00
vangel76 d8d1028b3f Merge remote-tracking branch 'upstream/main' into aep-container-alloc-3275 2026-11-08 03:17:17 +01:00
vangel76 38d51dd185 aep container: size sibling lists, hex and write output once; borrow plain .aepx attributes (#3275)
- read.rs: count the chunk headers of a sequence first and allocate the
  children Vec once (bounded by the input and by the chunk limit).
- aepx.rs: decode_hex sizes its output once; attribute values without
  an entity are borrowed instead of copied through decode_entities.
- typed.rs: PropGroup::get compares match names without building a
  String (same result as the lossy compare, invalid UTF-8 included).
- write.rs: reserve the exact output size up front (try_reserve, so a
  hand-built tree cannot abort on the allocation).
- read.rs, settings.rs, values.rs: use the shared bytes.rs readers.

Output is identical on the corpus (tree, written bytes, import).
2026-11-08 03:17:17 +01:00
vangel76 a18e3ce336 Merge remote-tracking branch 'upstream/main' into aep-export-template-3277 2026-11-08 03:15:24 +01:00
vangel76 8bf184a2d4 aep export: build the prototype template once, sort names with cached keys (#3277)
The template every export clones from is immutable; it is now built by the
first export of the process and kept (about 0.93 MB). The name sort builds
each natural key once instead of on every comparison. Root solids move into
the Solids folder instead of being copied. The two key-list rewrites share one
emit-local helper and match names compare as bytes instead of a decoded String.
Output is byte-identical.
2026-11-08 03:15:24 +01:00
vangel76 7694c11170 aep: a layer's markers and Source Text are read where they are stored, not searched for (#3276)
A layer's marker list is a direct child of its root tdgp, and its Source Text record
btds a direct child of the ADBE Text Properties group. Markers walked the whole layer
subtree twice per layer (most layers have no marker list, so the walk always ran to the
end), and the three text-document accessors walked it once each.
2026-11-08 03:10:16 +01:00
FredAppsandClaude Opus 5.5 ae35ea7d54 Preview: each stall doubles the frames the held sound waits for (#3260) (#3272)
* Preview: each stall doubles the frames the held sound waits for (#3260)

A preview that renders just below real time stopped its sound at the first
uncached frame, then started it again as soon as the silent preview kept up
with `ahead` frames cached. Those ran out within a few frames, so the sound
started and stopped over and over, which plays as distortion (#2473, #3260).

Each stall that stops the sound now doubles the cached frames ahead it waits
for before starting again, up to what fits in the RAM preview. A new preview
starts counting from zero.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Preview: cap the held sound's wait at frames the prefetch can keep cached

Once the doubling reached the RAM preview's `fit`, the held sound waited for
offsets 0..fit, but the prefetch only requests offsets below fit - 1, and
while the silent preview moves on its last requests are still rendering. The
sound then stayed silent almost to the end of the preview even after
rendering recovered.

The backoff now stops at half of the frames the prefetch requests, and never
below the wait before any stall. A new test caches only the frames playback
itself requests, with a RAM preview of `ahead + 2` frames.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 03:06:55 +01:00
Luis dbcae60e19 Release: refresh contributor credits for each release (#3189) (#3190)
About > Contributors still showed an old snapshot, because nothing
regenerated contributors/contributors.json before a release. Opt in to
the shared refresh from craft-common-actions: a read-only credits job
regenerates the snapshot for the release commit, and the shared release
workflow installs it before every source build. The snapshot is not
committed back.
2026-11-08 03:06:20 +01:00