Skip to content

Reverb / Limiter / Expander: carry streaming state across chunks (extends #72) #86

@matteospanio

Description

@matteospanio

Bug

#72 tracks the Compressor's per-forward() detector/envelope reset. The same applies to:

  • Expander/Gate (effect.py ~line 1800; expander_cpu.cpp / expander_forward.cu zero-init env each call)
  • Limiter (effect.py ~line 2036; envelope reset and the look-ahead window does not see the previous chunk's tail, so inter-chunk peaks are missed)
  • Reverb (effect.py:855; comb/all-pass delay lines re-zeroed per call — audible discontinuity at every chunk boundary in StreamProcessor use)

The native kernels (binding.cpp) take no state tensors at all, so chunked streaming cannot be state-continuous. This contradicts the streaming story: filters carry DF1 state across chunks, effects do not.

Fix

Thread optional state in/out through the native kernels (CPU + CUDA + bindings) and persist it on the Python effect objects, mirroring the IIR pattern (_state_*, lazy alloc, reset_state()):

  • Compressor/Expander: per-channel [C, 2] (envelope dB, RMS accumulator).
  • Limiter: per-channel envelope + carry the trailing lookahead input samples in Python so peak_env spans the chunk boundary.
  • Reverb: per-channel comb/all-pass delay-line buffers + damping state, allocated lazily at first forward.

CUDA mirrors need cluster validation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingeffectNew audio effectrealtimeReal-time / streaming

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions