You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Presets: stop the host's own echo dropping them back to Custom
The same bug an external user reported against vertigo as its issue #2, which
all seven plugins carried because the preset machinery was copied between them.
Choosing a factory preset in Resolume did nothing: the dropdown snapped straight
back to Custom.
applyPreset wrote its values into params[] and raised FF_EVENT_FLAG_VALUE so the
host would re-read its sliders. That rests on an assumption FFGL never makes.
The host owns parameter state; it pushes its own values back down whenever it
likes, and nothing obliges it to act on a value event. Resolume does not act on
them -- it carries on restating the values it still believes in, the ones from
before the preset. Those restatements arrive as SetFloatParameter calls carrying
a changed value, so the rule that a covered parameter changing means the
operator has taken over fired on the host's own echo, immediately, every time.
Three things now arrive through that one call while a preset is active and only
the third is a person, so they are told apart by what the value IS rather than
by the fact that it changed: matching the preset is the host agreeing with us,
matching hostValues[] -- the host's own last word, kept separately from what the
plugin renders with -- is the host restating itself, and anything else is an
edit. The first two are ignored rather than written. Ignoring rather than
writing matters for the first as well as the second: a host that quantises hands
back a ROUNDED copy of our own value, and the pre-existing "did a covered
parameter move?" test works to a tighter tolerance than this one and would read
that rounding as an edit.
seedHostValues() fills the record from the defaults on first parameter traffic,
which has to happen before applyPreset can run -- seeding afterwards records the
preset's own values as the host's opening position and the very next restatement
looks like an edit. That mistake was made once while writing this and the test
caught it.
Dropping to Custom is now logged with the parameter and value that caused it.
Diagnosing the original report needed a code read for exactly the reason orrery
issue #6 did: nothing said it had happened.
The harness grows --presets, which drives three hosts -- one that honours value
events, one that ignores them, one that honours them but quantises to 1/1000 --
across every preset, with no GL involved. Against the pre-fix code it fails in
precisely the "ignores" column, which is the shape of the bug as reported.
sweep.py also learns to stop at the About block, as porthole's already had:
those are browser buttons that never touch a pixel, and sweeping them reported
five dead controls and buried anything real.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: AGENTS.md
+43Lines changed: 43 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -313,6 +313,49 @@ still the only thing that measures anything.
313
313
314
314
## Factory presets
315
315
316
+
### The host owns the parameters, and a preset had to learn that
317
+
318
+
Reported against **vertigo** as its issue #2 and fixed across all seven plugins
319
+
on 2026-08-22: choosing a factory preset in Resolume did nothing and the
320
+
dropdown snapped straight back to `Custom`.
321
+
322
+
The pattern was copy-based — `applyPreset` writes the values into `params[]` and
323
+
raises `FF_EVENT_FLAG_VALUE` so the host re-reads its sliders — and it rests on
324
+
an assumption FFGL never makes. **The host owns parameter state.** It pushes its
325
+
own values back down whenever it likes, and nothing obliges it to act on a value
326
+
event. Resolume does not: it carries on restating the values it still believes
327
+
in, which are the ones from before the preset. Those restatements arrive as
328
+
`SetFloatParameter` calls carrying a changed value, so the rule "a covered
329
+
parameter changed, therefore the operator has taken over" fired on the host's
330
+
own echo, instantly, every time.
331
+
332
+
Three things now arrive through that one call while a preset is active, and only
333
+
the third is a person:
334
+
335
+
| What arrives | How it is recognised | What happens |
336
+
|---|---|---|
337
+
| the preset's own values, from a host that honoured the events | matches the preset | ignored — nothing to write |
338
+
| the values from *before* the preset, from a host that did not | matches `hostValues[]`, the host's own last word | ignored — writing it would undo the preset |
339
+
| a new value from neither | matches neither | written, and the preset falls back to Custom |
340
+
341
+
`hostValues[]` is the record of what the **host** last sent, which is not what
342
+
the plugin is rendering with, and `seedHostValues()` fills it from the defaults
343
+
on the first parameter traffic — **before `applyPreset` can run**. Seeding it
344
+
afterwards records the preset's own values as the host's opening position, so
345
+
the host's very next restatement looks like an edit; that mistake was made once
346
+
during the fix and the test caught it.
347
+
348
+
Two tolerances matter and they are not the same number. `kSame` is **1e-3**, a
349
+
host-quantisation allowance rather than a float epsilon — a host that keeps its
350
+
parameters shorter than a float hands back a number *near* ours. The pre-existing
351
+
"did a covered parameter move?" test below still works to 1e-4, which is why a
352
+
value matching the preset is **ignored rather than written**: letting a rounded
353
+
copy of our own value into `params[]` would trip that tighter test.
354
+
355
+
`octest --presets` drives all three hosts across every preset, with no GL
356
+
involved, and runs in `tools/verify.sh`. Against the pre-fix code it fails in
357
+
exactly the "ignores value events" column.
358
+
316
359
`source/Presets.h` is one table of named looks in the host-facing 0..1
317
360
parameter space, and it drives **both** builds — the FFGL constructor and the
318
361
OFX describe each read it, so a preset cannot drift between Resolume and
0 commit comments