fix(engines): restore MEMLCelium's feedback tap (L7)
feedback_/fbzm1_/fb_smooth_alpha_ were read every process() call but nothing ever wrote feedback_, so the path was silently inert. Git history shows this was a *muted* feature, not dead code: `feedback = v0 * feedbackGain` with feedbackGain 0.1f (MEMLCeliumAudioApp.hpp @d095688), then "0; //0.1f" — zeroed with the value kept in the comment — then the write was dropped entirely when the engine was ported to nisps/engines/ at the 2026-04-29 rewrite (8d0d47b). Operator decision: port it back, live at 0.1f. The tap is voice 0's own enveloped output, post-envelope and pre voice-1/mix/ shape — NOT the final output. This differs from PAFSynth's feedback shape; where the sibling and the reference disagreed, the reference won. Not schema-exposed: the reference hardcoded it, and MEMLCelium has no voice spaces to vary it by. If feedback depth becomes a research axis it wants to be a runtime parameter — noted, not built. Verification, and a gap worth recording: parity-check.sh PASSES (max delta 2.38e-7) but that is NOT evidence for this change — its harness only exercises PAFSynth and ChannelStrip, and the impulse baseline runs all-params-0.5, under which voice 0's sequencer never triggers, so v0_env stays 0 and the new write is 0 either way. That baseline is blind to this path, not a check on it. So it was cross-checked directly instead: sequencer params forced to trigger early, 4800 samples native vs WASM through the nisps_engine_* C ABI — native vs WASM max abs diff 1.19e-7 (tolerance 1e-5) all 4800 samples nonzero, finite, max amplitude ~0.99 (tanh-bounded) same run with gain forced to 0 diverges by up to 1.49 — not a no-op No fixture regenerated. nisps.wasm ships here because it is a tracked artifact under the Phase 0 freshness gate. Follow-up: the parity harness covers 2 of 8 engines. "Firmware and WASM share the same engines" is asserted repo-wide but tested narrowly.
This commit is contained in:
parent
c19d84619e
commit
1f38f1a7fb
2 changed files with 14 additions and 0 deletions
Binary file not shown.
|
|
@ -185,6 +185,10 @@ class MEMLCeliumEngine {
|
|||
const float p2 = v0_paf2_.play(freq2, freq2 + (v0_paf2_cf_ * freq2),
|
||||
v0_paf2_bw_, v0_paf_vib_, v0_paf_vfr_, v0_paf2_shift_, true);
|
||||
float v0 = (p0 + p1 + p2) * v0_env;
|
||||
// Feedback tap: voice 0's own enveloped output, one block behind (see
|
||||
// fbsmooth above) — matches firmware's `feedback = v0 * feedbackGain;`
|
||||
// taken at this same point (post-envelope, pre voice-1/mix/shape).
|
||||
feedback_ = v0 * feedback_gain_;
|
||||
|
||||
// ----- Voice 1 -----
|
||||
const float v1_env = v1_amp_env_.play();
|
||||
|
|
@ -293,6 +297,16 @@ class MEMLCeliumEngine {
|
|||
float feedback_ = 0.f;
|
||||
float fbzm1_ = 0.f;
|
||||
float fb_smooth_alpha_ = 0.5f;
|
||||
// Restored 2026-07-21 (finding L7): firmware history shows this went
|
||||
// 0.1f (live, `modes/AudioApps/MEMLCeliumAudioApp.hpp` @ d095688) -> "0;
|
||||
// //0.1f" (explicitly muted, value preserved in comment) -> the write
|
||||
// was dropped entirely when the engine was ported to nisps/engines/ at
|
||||
// the 2026-04-29 rewrite (8d0d47b) — feedback_/fbzm1_/fb_smooth_alpha_
|
||||
// kept being read in process() but nothing wrote feedback_, so the path
|
||||
// was silently inert. Operator decision: port it back live at 0.1f, not
|
||||
// muted. Not schema-exposed — a single fixed value (MEMLCelium has no
|
||||
// voice spaces to vary it by, unlike PAFSynth's feedback_gain_).
|
||||
float feedback_gain_ = 0.1f;
|
||||
};
|
||||
|
||||
static_assert(AudioEngine<MEMLCeliumEngine>, "MEMLCeliumEngine must satisfy AudioEngine");
|
||||
|
|
|
|||
Loading…
Reference in a new issue