Driven, not struck: diffuseur.h
This file exists because a plan was wrong in a useful way. The Ondes family
plan said the diffuseurs would inherit garden.h's modal machinery, and
they do — mode ratios, doublet splitting, per-mode decay. What it did not
say, and what reshaped the file, is that a diffuseur is driven. There is
no trigger here and no decay_env. The input excites the body continuously
and the body rings at its own rates, which is grm_comb.h's situation
rather than the chime's.
Five classes: mode, plate, sympathetic, harp, transducer, and two
cabinets over a shared cabinet base. Nothing else.
Unit peak gain, and everything it saves
mode is the constant-peak-gain two-pole resonator (Steiglitz; Smith,
Introduction to Digital Filters): poles at radius R, zeros at ±1, and
b0 = (1 − R²)/2.
That choice pays three times, and it is worth spelling out because it is the reason this file has almost no defensive code in it.
- Peak gain is 1 at any Q. So a bank of weighted modes is bounded by the sum of its weights. The plate's eight weights sum to exactly 1, which means the body cannot output more than its input, and there is no limiter anywhere in the file.
- Changing
decaydoes not change the level. With a plain two-pole resonator, moving R moves the peak gain, so a decay knob is also a volume knob. Here it is not. - The zeros at ±1 are exact nulls at DC and Nyquist. So there is no DC blocker on the body either. It cannot accumulate one.
None of that is novel — it is a textbook resonator used for the reason the textbook gives — but the cumulative effect on a file that runs sixteen of them plus twelve delay loops is large.
The order is the argument, and it is a bitwise test
The instrument's signal reaches the transducer first, and the transducer's motion excites the body. So the nonlinearity is upstream of the resonator.
That is the central design claim of the file, so it is pinned rather than
described: a scenario builds transducer → plate by hand and checks that a
whole metallique is bitwise identical to it, and that the reverse
wiring — resonate, then distort — differs by 28 % of peak.
Getting that null to be actually bitwise took one fix. cabinet::blend is
an equal-power crossfade written with cos/sin, and cos(π/2) in double
precision is 6.1e-17, not 0. A wiring test that reads 6.1e-17 has not
demonstrated identity; it has demonstrated approximate identity, which is
the thing the test exists to distinguish from. Both ends of the blend are
now exact short-circuits: mix 0 returns the dry input bit for bit, mix 100
returns the wet.
The transducer's bound is 2/saturation, not 1/saturation
The moving-iron model squares the drive, and vca::swing_shape bounds the
result at 1/saturation. The obvious test — output stays under
1/saturation — failed at 1.49 against a bound of 1.25.
The test was wrong, not the code. A hard-driven squared law produces a nearly-constant positive waveform: it sits up near the ceiling and dips toward zero. Removing its DC recentres that, so the excursion below the mean adds to the excursion above it, and the worst-case swing after the DC blocker is up to twice the saturator's own bound.
The corrected bound is 2/saturation, documented in the header, and the
scenario now asserts both sides of it — greater than 1/sat, less than
2/sat — so the test still catches the saturator disappearing entirely.
The general shape of this mistake is common enough to name: a DC blocker after an asymmetric nonlinearity is not free. It does not just remove an offset; it converts an offset into headroom you have to have.
A measurement that measured its own edges
The palme's selectivity scenario drives the board with a tone and measures what is still ringing after the tone stops. First version: switch the tone on, switch it off, measure the tail. It failed — 3.66× selectivity against the 4× asserted — and the failure was real but not about the strings.
Switching a tone on and off is a step, and a step is broadband. It excites every string on the board, so the tail contained twelve strings ringing regardless of what frequency had been played. The measurement was reading its own edges.
Fading the drive in and out over 250 ms removes the step. Every one of the twelve strings then passes, with the worst at 4.4×. The same fade is what the book figure uses, and the figure's caption says so, because a reader reproducing it without the fade will get the wrong answer.
Twelve strings
Widely copied hobbyist build pages describe the palme as two banks of twelve
strings. The peer-reviewed source (Wijnand, Boutin, Jossic & Maniguet, Forum
Acusticum 2023) says twelve, and k_strings = 12 with a comment saying
which source won and why.
Their tuning is not published anywhere found, so it is a parameter rather than a constant, and the header says that too. Guessing a tuning and hard-coding it would have been the same category of error as the twenty-four.
Where recreation begins
The instruments, their dates, their excitation and their transducer type are peer-reviewed. The modal data is not — no ondes-specific measurement of either body exists in any of the four sources read — so the plate uses Fletcher & Rossing's free circular plate (Rayleigh's Chladni ratios at Poisson 0.3) and the strings use the harmonic series.
This is stated in the header at the top rather than in a limits section at
the bottom, because it changes what the object is: a recreation of the
general physics, not a model of Martenot's instruments. The same applies to
asymmetry and saturation — the source establishes that the moving-iron
driver is nonlinear and that Thiele–Small does not describe it, and then
does not hand over a curve. Those two coefficients are voiced by ear and
labelled as voiced by ear.
A diffuseur with both at 0 is a linear resonator and is missing a real stage. That is a choice the caller may make, and the header says so rather than forcing a minimum.
Checkpoint
A textbook resonator chosen for three properties that between them remove
the limiter, the DC blocker and the decay/level coupling. A bitwise null
that pins the transducer upstream of the body, which required making an
equal-power blend exact at its endpoints. A saturator bound corrected from
1/sat to 2/sat because a DC blocker after an asymmetric nonlinearity
buys headroom, not just centring. A selectivity test that had to stop
measuring its own on/off step. And a provenance line drawn where the
published sources actually stop.