Skip to content

audiodynamics.Dynamics has no deinit() on the native builds, so no audioif-tier dynamics class can release one #60

Description

@bdbarnett

Stakes. Every audioeffects class of the audioif tier that builds a
audiodynamics.DynamicsCompressor, Limiter, Expander, NoiseGate,
DeEsser, TransientShaper, MultibandCompressor, DynamicEQ — cannot
release it on a board. The class gate's Tier 1 asks that deinit() release
every node the class built; on the two native builds
_component.Component.deinit() walks the class's node list, looks for
deinit with getattr(node, "deinit", None), and finds nothing to call. A
host that builds and tears down effects in a session leaks every Dynamics
it ever made. audioroute.Splitter is the same shape and is #58; this is its
sibling and the wider one — Limiter alone builds two per instance.

What the surface is. Measured this session, audiocomponents at
AUDIOIF_PIN 2f6cbc3, 2026-09-07:

$ .venv/bin/python -c "import audiodynamics; n = audiodynamics.Dynamics(
      audiodynamics.DYN_LIMIT, sample_rate=48000, channel_count=2)
  print(hasattr(n, 'deinit'), sorted(x for x in dir(n) if not x.startswith('_')))"
True  ['bits_per_sample', 'channel_count', 'deinit', 'gain_reduction_db',
       'key', 'max_buffer_length', 'play', 'playing', 'sample_rate',
       'samples_signed', 'set', 'single_buffer', 'stop']

$ MICROPYPATH=lib:../cmods/micropython/lib ../cmods/bin/micropython <same>
False ['bits_per_sample', 'channel_count', 'gain_reduction_db', 'key',
       'play', 'sample_rate', 'set']

$ MICROPYPATH=lib:../cmods/micropython/lib ../cmods/bin/circuitpython-effects <same>
False ['bits_per_sample', 'channel_count', 'gain_reduction_db', 'key',
       'play', 'sample_rate', 'set']

So the CPython shim has deinit, stop, playing, max_buffer_length and
single_buffer; the two native builds have none of them. The gap is the
native binding's, not the shared C's — audioif_dynamics.c has the state to
free.

What it costs the gate. docs/effects/Limiter-evidence.md §2 records six
partial cells for exactly this: the class's own surface still closes and
the borrowed source still renders, both measured, but "every node the class
built was released"
is unmeasured on MicroPython and on
circuitpython-effects, because there is nothing to observe. Every
audioif-tier dynamics pack in Phase 2 carries the same six cells, and the
gate audit rules them Y* with the cause below the class
(audiocomponents/docs/effects-phase2-gate-audit.md §3, G2).

Ask. deinit() on the native audiodynamics.Dynamics binding, with the
deinitialised guard #59 asks for generally. stop() and playing would
close the rest of the shim/native divergence, but deinit is the one a gate
item turns on.

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