Skip to content

audiodynamics.Dynamics: eleven additive options for the effects rewrite (detector, topology, side-chain, envelope) #38

Description

@bdbarnett

Effects program, Phase 0 — a surviving node ask. One issue per surviving node ask is the roadmap's last Phase 0 work item; this is one of eight. The candidate survived a two-refuter pass (audiocomponents/docs/effects-survey.md §"The node list"), and the body below is its design sketch, copied verbatim from that survey's §"Design sketches (survivors)".

Standing rules this ask is written under. It is additive, in an audioif-own module (D1, Brad 2026-09-06). No CircuitPython-ported node is modified — not by this ask and not by any of the 46 seeds. Defaults are chosen so an unset node is byte-identical to today, and the parity golden's diff must add only the new probe's digests with every existing digest unchanged. Nothing here is built before Phase 1.

Candidates 11–18 and 20–22, all surviving; 16, 20, 21 and 11 on a 1–1 split, each split reported in the survey with the losing argument intact.

# Option Traits it unblocks
11 DYN_TRANSIENT time constants exposed Exciter T5 (tau clause)
12 RMS detector Compressor V3, Expander E2, DeEsser D6
13 feedback detector topology Compressor F4, O5, M4, V5
14 BS.1770 true-peak detector Limiter L1
15 side-chain band (12 dB/oct + LP corner + key) Expander E3, NoiseGate G3, DeEsser D2
16 depth_db floor Expander E4 (NoiseGate G4 refuted by one vote)
17 four-stage gate envelope with hold NoiseGate G1/G2/G5/G7, Expander E5/E6
18 relative-threshold detection DeEsser D1, D2
20 program-dependent attack DeEsser D5
21 simultaneous attack + sustain gains TransientShaper T2
22 peak-hold on the slow envelope TransientShaper T4

Split before building. The sketch below is written for candidate 11 only. The other ten survivors are carried under it and have no sketch of their own — RMS detection, the feedback topology, the true-peak FIR, the side-chain band and key, the depth_db floor, the gate state machine, relative-threshold detection, the program-dependent attack, the second envelope pair and the peak-hold each need their own API line, state field and probe case. Phase 1 writes them before writing the C; the cost and latency arguments are in the survey's verdicts.

Default-off is load-bearing here. Any option added to audiodynamics must default off so dynamics_probe.py still hashes to vstaudio_dsp.c compiled unmodified (roadmap Phase 1 Work).


Design sketch (verbatim from the survey)

Module audiodynamics — four additive options on the existing own node.

API fast_attack_ms=1.0, fast_release_ms=50.0, slow_attack_ms=25.0, slow_release_ms=300.0, constructor and set(), plain floats (Dynamics.c:19-31 is scalar). Defaults are exactly the literals at audioif_dynamics.c:215/:217/:219/:221, so an unset node is byte-identical to today.

DSP Move those four audioif_dynamics_ms_to_coef() calls from process entry into audioif_dynamics_config_t as fast_attack_coef etc. Four enum entries appended after AUDIOIF_DYNAMICS_OPT_TRUE_PEAK (audioif_dynamics.h:36-47; that order is the bindings' keyword order, so append only), four rows in dynamics_option_names[]. Keep the sentinel: config_init leaves them 0.0f, config_finish fills 1/50/25/300 if still zero, as attack/release at :42-51. Arithmetic unchanged: float coefficients and envelopes (:286-289). Python owns Exciter's Transient Time macro — tau maps to the four times at the literals' ratios (tau/50, tau, tau/2, 6*tau); C sees four milliseconds.

Latency Zero: one-pole followers. lookahead_ms stays the node's only latency option, default 0 (audioif_dynamics.h:73-76).

Probe Extend dynamics_extras_probe.py, not dynamics_probe.py — the oracle never had these (docstring 5-10). Case 1 sets none and must match dynamics_probe.py's transient checksums byte for byte; then each option alone; then tau = 8/20/150 ms, measuring the step reaching within 1 dB of steady state in tau +/-25% (Exciter T5's clause). Planted fault: swap fast_att and slow_att, that measurement must fail.

Cost Nothing per sample; it removes 4 expf per process() call (:215-222). The transient path stays 256 frames x (2 muls :286-289 + 2 logf :291-292) + 256 expf (:310) per stereo block.

Note: this sketch is written for candidate 11. The other ten Dynamics survivors are carried under it and do not have sketches of their own — RMS detection, the feedback topology, the true-peak FIR, the side-chain band and key, the depth_db floor, the gate state machine, relative-threshold detection, the program-dependent attack, the second envelope pair and the peak-hold each need their own API line, state field and probe case. Phase 1 must write them before the audioif issues are filed; the cost and latency arguments are in the verdicts above.


Where this lands. Phase 1 of the effects program (docs/effects-roadmap.md Part II, Phase 1 — "The palette"). audioif is released once, at Phase 7, when the effects work is complete, so this node ships in that release and the AUDIOIF_PIN moves to the node commit at Gate 1, not to a tag.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions