First-order topology-preserving LP/HP/allpass¶
FirstOrderTptDesign::new(rate, cutoff_hz) prepares a first-order trapezoidal
profile on CONTROL. Rate is finite 1..768000 Hz; cutoff is strictly positive and
below actual Nyquist. It checks the original Hz relation, normalized ratio in
(0, .5), finite positive tan prewarp and representable gain/complement/stable pole.
Collapsed ratios or rounded endpoints reject without nudging. quantize_f32
explicitly validates the rounded native f32 profile again. Requested rate/cutoff
metadata and actual gain are separate; magnitude_at observes the actual
coefficient's ideal LTI spectrum for normalized frequencies 0.. .5. This is not
an all-input floating recursive error bound or transferred f64 spectral guarantee.
The observation uses stable half-angle components Gcos(pif) and
(1-G)sin(pif), avoiding cancellation of 1-p near admitted endpoints.
Existing biquad and second-order state-variable defaults remain unchanged.
The coefficient is g = tan(picutoff/rate), G = g/(1+g). Solve the first-order feedback equation y = g(x-y) + s around a trapezoidal integrator: v = G*(x-s), low = s+v, capacitor next = low+v, high = x-low, all = low-high. This circuit is covered mathematically in Zavalishin's filter book, sections 3.6–3.9. The runtime owns the signed capacitor state, which is distinct from the previous lowpass output.
FirstOrderTptFilter and its 32 variant advance once and return named simultaneous
FirstOrderTptOutputs /32 for LP, HP and allpass. LP+HP reconstructs input in ideal
arithmetic; native summation can round. The fixed allpass has unit ideal magnitude
and frequency-dependent phase. With p = 1-2G and q = z^-1, LP is
G(1+q)/(1-pq), HP is (1-G)(1-q)/(1-pq) and allpass is (-p+q)/(1-p*q).
Requested quarter-rate cutoff has ideal half gain; the local native f64 tan/prewarp
fixture produces G = 0.49999999999999994, while explicit f32 quantization produces
0.5 and the exact dyadic average/difference/one-sample-allpass fixture. Actual
coefficients are retained rather than repaired to ideal landmarks.
set_design preserves the signed capacitor state; replace_design resets it.
Callers can preprepare coefficient schedules and select profiles in the callback
without trig or allocation. There is no implicit smoothing, crossfade, inaudibility
or arbitrary modulation stability guarantee. Selected-response separate blocks
preflight equal lengths before output/history edits, in-place blocks retain scalar
order, and empty blocks advance nothing. Response selection does not reset history.
reset_to accepts a finite signed capacitor state, with invalid initialization
preserving the original state. snap_to_zero is caller-only and clears strictly
subnormal signed state, preserving normal/nonfinite history; blocks never snap.
FirstOrderTptBank and its 32 variant own 1..64 independent channel states with
maximum blocks 1..65536 and a shared immutable profile. Per-channel processing
returns all three responses from one update. Planar separate/in-place processing
selects a response and preflights every channel count, active prefix and frame
bound before any output/state edit. Backing suffixes remain untouched; empty
prefixes consume nothing. Set preserves all channel states, reset/replace clears
all, and validated reset-to initializes all together. Construction, runtime and
reset use fixed storage without framework heap allocation, locks or I/O. Caller
block sizes still bound work.
Nonfinite input and large finite arithmetic overflow propagate and can poison history until reset. There is no numeric scan, finite-output sanitizer, headroom repair, processor-wide denormal mode, SIMD or callback deadline claim. The ideal recursive tail is infinite; actual product rounding may retain subnormal state until caller snapping. There is no finite EOF flush, constant integer latency, aligned dry path or alias-free modulation promise.
Independent analog/bilinear spectrum, polynomial impulse/time and signed initial/ sample-varying circuit equations qualify both precisions and responses. All channel counts, prefix/partition/suffix/state/error/poison/snap and heap fixtures are tested. Actual canonical native stereo Foundation/Graph consumers use distinct rapidly changing profiles and an existing f64 FIR downstream; the f32 fixture's FIR conversion is caller-explicit, with its Foundation buffer and TPT core staying native f32. Offline composition is not physical device, DAW, platform or acoustic support evidence.
Prepared panning curves and pair ramps¶
PanningGains prepares seven explicit curves for finite pan -1..1:
Linear, Balanced, Sine, SineThreeHalves, SineSquared,
SquareRoot, and ThreeQuarterPower. With u=(pan+1)/2, linear uses
[1-u,u], balanced uses [min(1,2(1-u)),min(1,2u)], sine uses
[cos(πu/2),sin(πu/2)], the two sine variants raise these gains to 1.5
or 2, and the last two raise [1-u,u] to .5 or .75. These are the actual
mathematical exponents; center attenuation is approximately 3.0103,
4.51545 or 6.0206 dB, rather than an exact rounded decimal label.
The caller selects PanningNormalization::UnityEndpoints or
UnityCenter. The latter scales by the rounded reciprocal of each law's center gain so both
center coefficients are one; endpoints can then be amplified by √2,
2^.75 or 2. Balanced needs no boost. Unity endpoints sine and
square-root have constant ideal summed power. Other laws, center
normalization, coherent fold-down and arbitrary correlated stereo
material do not share a universal loudness rule. Endpoint/center cases
are explicit, and mirrored pans swap identical actual gains. Private
immutable metadata exposes the requested pan/law/normalization and
actual coefficient pair. quantize_f32 explicitly rounds coefficients
into PanningGains32; actual f32 power can differ from the ideal curve.
StereoPanner / StereoPanner32 require prepared gains, an explicit
ramp duration 0..u32::MAX frames and maximum block 1..65536. Stereo
processing balances the existing two channels independently, without
crossfeed. The mono method explicitly duplicates one source into two
outputs. Both gains advance exactly once per audio frame; scalar,
separate prefix and stereo in-place prefix methods share this progress.
Every prefix checks channel counts, every active length and maximum
before gains or output change; inactive suffixes stay untouched and
empty prefixes advance nothing. Scalar calls do not impose a block
length. Construction, design, control and processing allocate nothing
and use no framework locks or I/O. Trigonometry/powers occur only in
prepared CONTROL design.
After a changed target, the first frame interpolates 1/N from current
actual gains and frame N assigns the exact target. Zero duration is
immediate. Repeating identical target coefficients retains progress,
including a different curve/normalization that has the same actual
pair; target metadata still updates. Mid-ramp retargeting starts from
current rounded gains. Reset snaps to the latest target. Both native
variants interpolate coefficients in f64; coefficient rounding and
sample multiplication use the named precision. Intermediate pairs may
leave the static curve and need not maintain constant power. Very long
ramps can repeat coefficients despite exact pending-frame counts. No
implicit millisecond conversion is applied; callers can use
smoothing_samples explicitly.
Nonfinite samples multiply naturally, including 0×infinity producing NaN; controls remain usable because there is no input history. Finite boosted inputs can overflow. This is not clipping, limiting, spatial crossfeed, correlation compensation, a deadline/SIMD qualification or latency compensation. Actual native mono/stereo Foundation→Graph consumers exercise changing full-family controls and downstream FIR; the f32 fixture explicitly converts to/from the existing f64 FIR. That fixture does not claim native f32 FIR support. A paired dry/wet FIFO with wet-latency compensation remains an independent capability.
Paired dry/wet queues and wet-latency compensation¶
DryWetGains prepares a finite wet fraction0..1 directly, using the
same seven PanningLaw curves and two explicit normalizations as
panning. Preparing wet directly preserves a tiny wet coefficient that
would disappear if converted through pan=2*wet-1. Actual coefficients
can still underflow or round in their named precision. quantize_f32
creates native DryWetGains32 while retaining requested fraction,
curve and normalization; center normalization can boost weights up to2.
No curve provides universal compensation for arbitrary correlation.
DryWetMixer / DryWetMixer32 have explicit channels1..64, maximum
block1..65536, FIFO1..65536 frames, maximum wet latency0..4194300
samples, DelayInterpolation and ramp duration0..u32::MAX frames in
DryWetMixerConfig. The individual bounds do not override the checked
aggregate32MiB budget for native queue/history and fixed recursive
values. Construction validates the declared budget before fallible
reservations, then checks actual capacities. Allocation and disposal
belong to CONTROL. Push, mix, validated edits and reset use no heap,
framework locks or I/O; reset visits all prepared history/queue storage.
push_dry preflights the entire prepared channel/prefix/max/free-space
and u64 accepted-frame count before accepting a call. It advances each
channel's causal delay exactly once per source frame and queues
already-delayed dry values. It does not advance mix gains.
mix_wet or mix_wet_in_place validates every channel/active length,
maximum, queued dry availability and consumed u64 count before changing
queue, gains or output. Each consumed frame advances one shared pair
ramp once, then every channel computes delayed_dry×dry_gain +
wet×wet_gain in its native precision. Products and addition are explicit,
without hidden FMA or normalization repair. FIFO batch partitions can
differ and wrap; pending suffixes are retained. Overrun/underrun reject
the complete call, preserve owners and output, and are not silently
filled or dropped. Empty prefixes advance nothing; inactive backing
suffixes stay untouched. Counters describe the accepted/consumed epoch
since reset, rather than host/device time.
For requested d=n+f, dry reconstruction is causal: Integer truncates
to tap n; Linear combines n/n+1; Lagrange3rd evaluates nodes
n..n+3 at f; Thiran1st applies a=(1-f)/(1+f) and
y=a×v+previous_v-a×previous_y to tap v at n. Initial history is zero.
An integer-valued Thiran delay bypasses recursion and updates both prior
values. No
hidden minimum latency is added. Native32 rounds f explicitly and
rejects a nonzero FIR/Thiran fraction that becomes0 or1; Thiran also
rejects actual a rounded to1. Integer deliberately floors instead.
Requested delay and actual native fraction/coefficient getters are
distinct. The fraction is unused for Integer and can round to1 in native32
while the executed tap remains floor(requested). The coefficient a is used
only by fractional Thiran; other policies and its integer bypass ignore it.
Gain-pair interpolation uses f64; delay weights/recursion and sample products
use the named native precision. Linear/cubic are not
broadband ideal delays, and cubic can overshoot. Fixed noninteger Thiran
has unity ideal magnitude and requested DC group delay up to native
rounding, frequency-varying group delay and an infinite alternating tail.
set_wet_latency_samples rejects changed latency while dry is queued;
exactly identical requested delay is an idempotent no-op. An accepted
edit preserves causal/recursive histories and retaps immediately, with
no smoothing/crossfade or modulation guarantee. set_target follows
the pair ramp's exact consumption-frame policy, including retained
progress for identical actual gains and refreshed metadata. Push-only
intervals and failed consume calls advance no ramp. Reset clears pending
dry, delay history and counter epoch and snaps gains to the latest target,
while retaining latency/configuration/storage.
Callers supply wet samples in order from the same source processing sequence and declare the wet path's actual latency. The mixer does not authenticate content/timestamps, estimate latency, delay wet, reorder frames or repair missing dry pushes. Callers explicitly push/mix zeros for any desired tails; no EOF or automatic finalization is implied. Nonfinite audio can poison delay history until reset and finite boosted mixes can overflow. This is not sanitization, limiting, a host latency report, a hardware clock, a native deadline/SIMD qualification or broad physical alignment claim. Actual native three-channel Foundation→Graph consumers exercise differently batched dry and a real wet FIR with a caller-selected three-sample delay. The native32 fixture explicitly bridges to the existing f64 FIR; it does not claim native32 FIR support.
The fractional-latency composition fixture separately uses a symmetric six-tap wet FIR with group delay2.5 and Linear dry compensation at2.5. Half dry minus half wet cancellation is measured through actual native64/native32 three-channel Graph callbacks, including differently batched push/consume, reset/reprepare, late maximum rejection and zero callback heap. The independent finite convolution and closed response distinguish common phase from unequal magnitude: its low- frequency null amplitude is bounded by0.7×(2πf)^2 per unit input in ideal arithmetic, with native rounding qualified separately. It does not promise broadband exact cancellation. Native32 explicitly bridges to the f64 FIR. Largest admissible fractional taps near maximum17, including cubic tap19, are independently compared across repeated history/FIFO wraps in both precisions. Denormal handling remains caller policy, including the infinite Thiran tail.
Six-stage modulated feedback phaser¶
Phaser / Phaser32 own six first-order TPT allpass histories per channel,
a previous wet feedback value and one shared base LFO phase. PhaserConfig
requires finite sample rate8000..768000, channels1..64 and maximum block1..65536.
PhaserControls has no implicit defaults: rate0 freezes phase, otherwise
.001..100Hz; depth0..1; finite center frequency; feedback[-.99,.99]; wet mix0..1;
and adjacent-channel phase offset0..1 cycles. Depth means a maximum four-octave
half-span: fc=center×2^(4×depth×sin(2πphase_channel)), and each channel adds
channel_index×offset modulo one cycle. Channels do not crossfeed.
Preparation and complete control replacement validate the original floating Hz sweep extrema and normalized endpoints[1e-6,.49], plus actual native design representability, before owner mutation. A requested center/depth whose full sweep leaves that profile rejects; there is no clamp, nudge or coefficient repair. A private already-admitted design path shares the existing public first-order coefficient expressions and recurrence, making frame updates infallible inside this profile. Public first-order validation/defaults stay unchanged. Tests inspect floating sweep extrema and endpoint/interior coefficient equivalence in both precisions. Getters expose requested controls, actual native feedback/mix, next-channel cutoff/gain and floating sweep bounds.
Each frame samples base phase before advancement and computes the explicit per-channel sine/exp2/prewarp. F64 phase and transcendental preparation are used in both variants; coefficient and recurrence/audio arithmetic use the named precision. Cascade input is x+feedback×previous_wet, with feedback0 bypassing that multiplication. Six allpass outputs form wet, which becomes next feedback history. Wet mix0/1 returns exact dry/wet endpoints; dry still advances the complete wet path and phase without leaking0×poison into dry output. One base phase step occurs per frame, regardless of channel count. Frame and separate/in-place planar prefix methods validate all channels, lengths and maximum before state/output mutation; empty prefixes advance nothing and inactive suffixes stay untouched.
Controls replace together and retain all histories/base phase. Reset clears all stages/feedback and base phase; reset-to-phase validates finite[0,1) before clearing. Construction/control/processing/reset use fixed storage, no framework heap, locks or I/O. Trigonometry/exp2/tan per frame/channel are explicit work, with no cheap-LFO or native deadline inference. Floating phase progress need not equal an ideal arbitrary-duration oscillator exactly. A finite one-million-frame768k/.001Hz observation had maximum circular ideal phase difference1.863e-14; the8000/100Hz10001-frame wrap fixture had1.782e-13. These are finite observations qualified against a rounding accumulation bound.
At fixed actual gain G, p=1-2G and A=(-p+z^-1)/(1-p×z^-1), giving wet transfer W=A^6/(1-feedback×z^-1×A^6). Zero-feedback half mix has three cancellation notches: f=atan((G/(1-G))×tan(π/12,π/4,5π/12))/π. DC/Nyquist wet gains are 1/(1-feedback) and1/(1+feedback). This can amplify headroom substantially. Static ideal allpass/small-gain facts are distinct from executed rounding, arbitrary modulation stability or broadband pure delay. Recursive tails are infinite and no constant integer latency/host report or implicit EOF flush is provided. Native nonfinite/overflow audio can poison histories until reset; retuning clicks/aliasing/denormals/saturation/limiter/SIMD/deadline policy remain caller-owned.
Independent nodal and polynomial time oracles, rational transfer/notch observations and a seven-state matrix-power tail certificate qualify selected static profiles. For nine static profiles (normalized cutoffs.07/.13/.25, feedback-.99/0/.99), six frequencies and131072frames/profile, native64 maximum time/spectrum deviations were3.33e-14/1.69e-11. Native32 measured maximum time error1.104e-6, complex spectrum error1.470e-4 and normalized error/(1+|H|)=3.062e-6 against the ideal actual-coefficient response; its fixture uses4e-6×(1+|H|). This is selected finite rounding qualification, not a universal analytic error bound or perfect executed allpass assertion. Tail certificates use the independent static state model, not feedback alone. Actual native three-channel Foundation→Graph consumers exercise changing complete controls, real downstream FIR, lifecycle, callback preflight and heap freedom. The native32 fixture bridges explicitly to the existing f64 FIR, without a native32 FIR or physical/device/DAW/real-time support claim.