mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-10 04:21:25 +00:00
AEP import: Echo keyframe regression for the range loss
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
495221aac6
commit
c32aa7cfbc
2 files changed
+52
No files matched your search
@@ -24,6 +24,7 @@ fn echo(values: Vec<(usize, f64)>) -> Fx {
|
||||
],
|
||||
values,
|
||||
data: vec![],
|
||||
keys: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +37,7 @@ fn hdr_highlight_compression_amount() {
|
||||
defs: vec![slider(K::FloatSlider, "Amount", 100.0, (0.0, 100.0))],
|
||||
values,
|
||||
data: vec![],
|
||||
keys: vec![],
|
||||
};
|
||||
// `hdr-01-set-all`: 90; `hdr-00-defaults`: no record, 100.
|
||||
for (values, want) in [(vec![(1, 90.0)], 90.0), (vec![], 100.0)] {
|
||||
@@ -79,6 +81,24 @@ fn echo_values_beyond_effectcrafts_range_are_reported() {
|
||||
near(&g, "decay", 100.0);
|
||||
}
|
||||
|
||||
/// A keyframed Echo parameter keeps its keys as stored and reports the range loss.
|
||||
#[test]
|
||||
fn echo_keys_beyond_effectcrafts_range_are_kept_and_reported() {
|
||||
// Number Of Echoes keyed 10 -> 30 000: the second key is beyond EffectCraft's 255.
|
||||
let mut fx = echo(vec![]);
|
||||
fx.keys = vec![(2, vec![(0, 10.0), (1000, 30000.0)])];
|
||||
let (g, r) = run(&fx, "ec.time.echo");
|
||||
let found = losses(&r, LossCategory::Effects, "ADBE Echo");
|
||||
assert_eq!(found.len(), 1, "{found:?}");
|
||||
assert!(found[0].contains("Number Of Echoes") && found[0].contains("30000") && found[0].contains("0 to 255"), "{found:?}");
|
||||
assert!(losses(&r, LossCategory::DamagedData, "ADBE Echo").is_empty());
|
||||
// Both keys arrive with their values.
|
||||
let g = g.expect("still imported");
|
||||
let keys = &g.prop("numberOfEchoes").expect("numberOfEchoes").keys;
|
||||
let values: Vec<Value> = keys.iter().map(|k| k.value.clone()).collect();
|
||||
assert_eq!(values, [Value::Scalar(10.0), Value::Scalar(30000.0)]);
|
||||
}
|
||||
|
||||
/// Linear Wipe's values, set and default.
|
||||
#[test]
|
||||
fn linear_wipe_values() {
|
||||
@@ -92,6 +112,7 @@ fn linear_wipe_values() {
|
||||
],
|
||||
values,
|
||||
data: vec![],
|
||||
keys: vec![],
|
||||
};
|
||||
// `linwipe-01-set-all`.
|
||||
let (g, r) = run(&fx(vec![(1, 10.0), (2, 77.0), (3, 16.0)]), "ec.transition.linearwipe");
|
||||
@@ -113,6 +134,7 @@ fn offset_blend_is_a_fraction_and_the_centre_a_point() {
|
||||
defs: vec![other(K::Point, "Shift Center To", Default::Point(0.5, 0.5)), slider(K::FixedSlider, "Blend With Original", 0.0, (0.0, 1.0))],
|
||||
values,
|
||||
data: vec![],
|
||||
keys: vec![],
|
||||
};
|
||||
// `offset-02-chk-toggled`: Blend With Original stored 1.0 is 100 %.
|
||||
let (g, r) = run(&fx(vec![(2, 1.0)]), "ec.distort.offset");
|
||||
@@ -139,6 +161,7 @@ fn color_stabilizer_points_sample_size_and_stabilize() {
|
||||
],
|
||||
values,
|
||||
data: vec![],
|
||||
keys: vec![],
|
||||
};
|
||||
// `colstab-00-defaults`: Levels, the points at 20 %, 50 % and 80 % of the width.
|
||||
let (g, r) = run(&fx(vec![]), "ec.color.colorstabilizer");
|
||||
|
||||
@@ -130,6 +130,27 @@ fn record(template: &Chunk<'_>, v: f64) -> Chunk<'static> {
|
||||
Chunk::list(*b"tdbs", kids)
|
||||
}
|
||||
|
||||
/// A keyframed value record: `record`'s header with a key list of linear one-component keys.
|
||||
fn keyed_record(template: &Chunk<'_>, keys: &[(i32, f64)]) -> Chunk<'static> {
|
||||
let Body::List { children, .. } = record(template, keys.first().map_or(0.0, |k| k.1)).body else { unreachable!("record builds a LIST") };
|
||||
let mut children = children;
|
||||
let mut lhd3 = vec![0u8; 52];
|
||||
lhd3[0..4].copy_from_slice(&0x00d0_0beeu32.to_be_bytes());
|
||||
lhd3[8..12].copy_from_slice(&(keys.len() as u32).to_be_bytes());
|
||||
lhd3[16..20].copy_from_slice(&48u32.to_be_bytes());
|
||||
let mut ldat = Vec::new();
|
||||
for (time, value) in keys {
|
||||
let mut rec = vec![0u8; 48];
|
||||
rec[0..4].copy_from_slice(&time.to_be_bytes());
|
||||
rec[4] = 1;
|
||||
rec[5] = 1;
|
||||
rec[8..16].copy_from_slice(&value.to_be_bytes());
|
||||
ldat.extend(rec);
|
||||
}
|
||||
children.push(Chunk::list(*b"list", vec![Chunk::data(*b"lhd3", lhd3), Chunk::data(*b"ldat", ldat)]));
|
||||
Chunk::list(*b"tdbs", children)
|
||||
}
|
||||
|
||||
/// An effect instance: its match name, display name, parameter definitions (after the input
|
||||
/// layer, before the built-in entry), the 1-D values stored (`parT` index, value) and the
|
||||
/// arbitrary data stored (`parT` index, bytes).
|
||||
@@ -139,6 +160,9 @@ pub struct Fx {
|
||||
pub defs: Vec<Def>,
|
||||
pub values: Vec<(usize, f64)>,
|
||||
pub data: Vec<(usize, Vec<u8>)>,
|
||||
/// Keyframed 1-D parameters (`parT` index, (time units, value) per key), linear keys; the
|
||||
/// parameter then has no entry in `values`.
|
||||
pub keys: Vec<(usize, Vec<(i32, f64)>)>,
|
||||
}
|
||||
|
||||
/// The match name of parameter `i` of `fx` (`<match>-NNNN`).
|
||||
@@ -172,6 +196,10 @@ fn sspc(fx: &Fx, template: &Chunk<'_>) -> Chunk<'static> {
|
||||
values.push(Chunk::list(*b"aRbs", vec![Chunk::data(*b"aRbp", d.clone())]));
|
||||
}
|
||||
}
|
||||
for (i, keys) in &fx.keys {
|
||||
values.push(tdmn(¶m_name(fx, *i)));
|
||||
values.push(keyed_record(template, keys));
|
||||
}
|
||||
Chunk::list(*b"sspc", vec![nested(*b"fnam", vec![utf8(fx.name)]), Chunk::list(*b"parT", part), Chunk::list(*b"tdgp", values)])
|
||||
}
|
||||
|
||||
@@ -306,6 +334,7 @@ fn pard_layout_decodes_as_written() {
|
||||
],
|
||||
values: vec![(1, 20.0)],
|
||||
data: vec![],
|
||||
keys: vec![],
|
||||
};
|
||||
let bytes = bytes_with(&fx);
|
||||
let file = parse(&bytes).unwrap();
|
||||
|
||||
Reference in new issue
Block a user