Add advance(numSamples) so the engine can step LFOs per sub-block
instead of calling process() in a sample loop. process() now
delegates to advance(1).
Split phaseOffset from phase so setParams doesn't overwrite the
running phase; getPhase() adds the offset and wraps. Fix sync mode
to divide by beat multiplier instead of multiplying. Move SampleHold
randomization into advance() based on cycle count. Validate shape
data in setShapeData with isfinite and jlimit.
Add bounds, finiteness, and range clamping to addConnection and
addAssignment. Validate ValueTree types and property values in
fromValueTree before inserting, rejecting non-integer indices and
unknown source names. Run toValueTree through a validated copy to
ensure persisted state is always within constraints.
Replace the single shared array of 9 effect units with a 2D array
of kNumFxSlots × kNumEffectTypes, so each slot owns its own DSP
state. This prevents state bleed when the same effect type appears
in multiple slots and allows reordering without carrying over
internal history.
Track activeTypes to skip unchanged slots. Remove the dry buffer
since it was unused.
Add updateCoefficients() that short-circuits when cutoff, resonance,
and type are unchanged. Cache ladderG and formantCoefficients so
processSample() avoids redundant exp()/tan() calls per sample.
Extract static getCutoffHz() from Filter::process() so FilterBank
can compute the keytracked cutoff once per parallel branch instead
of per sample. Simplify formant() and screamer() signatures to use
cached state.
Introduce paramIds namespace with Oscillator struct and constexpr
arrays for envelope, LFO, FX, and macro parameter IDs. Replace the
scattered local const char* arrays in Engine and PluginEditor with
references to these shared definitions.
Return ModSource::Count from modSourceFromString for unknown strings
instead of silently mapping to Lfo1. Simplify isPerVoiceSource and
isPerVoiceTarget to range-based expressions.
Add a floating value label near the cursor while dragging a knob, giving
immediate feedback without altering slider behaviour. Inherit
SettableTooltipClient on ToggleButton so setTooltip works consistently
with knobs and combos.
Introduce a shared layout constants namespace in PluginEditor so every
panel, row and control position derives from one spacing system. Add
tooltips to all knobs, combos, toggles, and buttons. Add Tab/Shift+Tab
tab cycling via keyPressed, with a TooltipWindow for hover hints.