History#

0.5.0 (2026-09-28)#

  • Fix GPU training (#231): model_response excites the model on its own device, wrap_fdn_shell / dss_to_flamo / trainable_from_build build the FFT layers on the requested device, and train_fdn now defaults to the model’s device instead of the CPU. Requires flamo>=0.2.20, whose canonical module devices let device="cpu" / "cuda" mix with .to(...) (previously Shell rejected them as different devices).

  • import pyFDN no longer loads torch or flamo, which makes it about three times faster; the training API and flamo_to_pr load on first use. Every public name is still exported from pyFDN.

  • construct_cascaded_paraunitary_matrix (and the velvet / random_dense gallery types), shift_matrix_distribute and random_matrix_shift are now reproducible with np.random.seed; they used an unseeded generator before. random_orthogonal takes an optional rng.

  • process_dss renders through the same graph as dss_to_td (one time-domain engine), with identical output. dss_to_td / build_to_td now accept a td operator or any process_block object as a hook, and run post_delay on the delay output in real time.

  • Breaking: delay state-space arguments are (delays, A, B, C, D) everywhere: dss_to_flamo(delays, A, B, C, D, fs, ...), is_allpass(delays, A, B, C, D) and dss_to_impz(delays, A, B, C, D, ir_len).

  • Breaking: pole_boundaries takes the absorption as an (sections, 6, N) SOS bank (the FDNBuild.post_delay format) instead of an object with b and a fields, and accepts a 2-D feedback matrix.

  • Breaking: tiny_rotation_matrix and rotation_matrix_from_angles return NumPy arrays (the dtype argument is gone) and draw from NumPy’s random state.

  • fdn_system_gallery and filter_matrix_gallery use snake_case type names like fdn_matrix_gallery ("nested_allpass", "allpass_in_fdn", "velvet", …); the old spellings are still accepted.

  • plot_FDN_build is now plot_fdn_build; the old name remains an alias.

  • Breaking: Plotly is gone; every plot function returns a Matplotlib figure, built without pyplot. animate returns a Matplotlib FuncAnimation (show it with .to_jshtml(); the Plotly-only transition_ms argument is removed), SDN.visualize draws a Matplotlib 3-D axes, and the Plotly helpers downsampled_scatter and downsample_plotly_trace are removed. The example notebooks use Matplotlib throughout, and plotly is no longer in any extra.

  • flamo_to_pr no longer prints progress by default (verbose=False, like dss_to_pr). matrix_sqrt keeps float64 precision.

  • edc accepts torch tensors and shares its Schroeder integral with energy_decay_curve and the decay losses.

  • Remove the pyFDN.auxiliary.coupled_rooms module (a hand-wired FLAMO FDN used only by its test; example_coupled_rooms covers the model) and the unused flareverb dependency.

  • Internal: generate/ is consolidated into orthogonal.py, paraunitary.py and structures.py; dss_to_flamo and trainable_from_build share one FLAMO core builder; the residue extraction, device default, tensor conversion and seed handling exist once. CI now runs ruff and mypy.

  • Add Match, a composable response loss that extracts a feature from the model response and the reference (waveform, magnitude, phase, mel magnitude, multi-resolution spectrogram, octave-band EDC, cumulative energy), compares them with a distance (squared, absolute, circular, …) and reduces the result to a scalar. The reference feature is cached across steps. FlatMagnitude, FlatSpectrogram, MatchMagnitude, MatchImpulseResponse, MatchEnergyDecay and MatchCumulativeEnergy are now built on it, with unchanged values.

  • Add the losses SpectralFlatness (geometric over arithmetic mean of |H|, gain-invariant), MatchPhase and MatchPhaseSpectrogram (circular phase distance, whole-response and multi-resolution STFT) and MatchMelMagnitude (mel-filterbank magnitude).

  • Add the differentiable features energy_decay_curve (Schroeder EDC) and mimo_rir_eigenvalues_per_frequency (eigenvalues of a square MIMO transfer matrix per frequency bin).

  • Add the Kronecker feedback matrix of Coppola (DAFx26): kronecker_matrix builds a lossless 2**M x 2**M matrix from M two-by-two rotation or reflection kernels, one angle each, and kronecker_transform applies it in O(N log2 N) with the paper’s in-place butterfly instead of a dense product. Every kernel angle addresses one bit of the delay-line index, so a single angle cuts or re-couples the network along one partition – the outermost across the two stereo halves, the innermost between the even- and odd-indexed lines – and the matrix stays orthogonal at every setting. All reflection kernels at pi/4 recover the normalised Hadamard matrix, so the usual FDN mixing matrix is one point in the family. Reachable from the gallery as fdn_matrix_gallery(N, "kronecker"), with kronecker_angles for naming the angles to move.

  • Add the td.KroneckerMatrix and td.TimeVaryingKroneckerMatrix operators. The latter modulates chosen kernel angles by a sine or triangle, which breaks up fixed modal resonances by moving the poles without the chorusing that modulating the delay lengths brings; since only one two-by-two kernel changes per moving angle, per-sample modulation costs no more than the static matrix. Both go straight into the post_matrix hook of process_dss.

  • Add the example_kronecker_matrix notebook, which reproduces the configurations from the paper’s companion site: the construction and its Hadamard special case, the fast transform, the stereo cross-coupling sweep on the outermost angle with its interchannel-balance and IACC analysis, and matrix modulation on the next angle in, with the pole-frequency histogram that shows why it reduces coloration.

  • Breaking: the ten-band graphic EQ’s command grid is now the octave centres 31.25 Hz through 16 kHz, with nearest-neighbour hold below 31.25 Hz and above 16 kHz, instead of dummy DC and Nyquist anchors at 1 Hz and fs. The 10-vector of gain_to_geq / decay_to_geq / AttenuationFilter / OutputEQ targets is ordered on pyFDN.eq.COMMAND_FREQUENCIES. The 11-section cascade itself is unchanged.

  • Fix the first-order shelf bilinear prewarp: first_order_shelf_biquad used tan(ω) rather than tan(ω/2), so a requested crossover sat at twice the named frequency. High crossovers are now clamped at fs/2.1 (Nyquist-safe for the corrected prewarp) instead of fs/5. The default midpoint is fs/4. example_reverberation_enhancement uses a challenge gain of 1.6.

  • example_train_fdn_to_rir now fits on a shorter FFT grid than it measures on. The loss only needs enough of the decay to steer on, while the octave-band estimators need a longer measurement window, so the notebook trains at nfft=2**16 (1.37 s) and switches to 2**17 (2.73 s) with FLAMO’s new Shell.set_nfft before rendering. The step cost is linear in nfft, so shorter grid reduces training time. Each training-cell run resets the grid before fitting. Requires flamo>=0.2.18, where set_nfft was added. The walkthrough now focuses on the implemented workflow and ends with octave-band validation. Keep a CPU/CUDA float32 selector and use first-order shelves for absorption and output EQ. Cite the filter-learning paper with a TODO for publication.

  • Type every DSS matrix parameter (A/B/C/D and the b/c/d gains in dss_to_ss) as ArrayLike instead of ndarray across dss_to_flamo, dss_to_impz, dss_to_td, dss_to_tf, dss_to_ss, general_char_poly, and loop_tf – matching what these functions already do internally (np.asarray(...)) and how delays was already typed. Also fixes dss_to_ss silently returning a non-array dd when d was passed as a list rather than an ndarray.

  • Add dss_to_td, the raw delay state-space (DSS) counterpart of build_to_td – matching the dss_to_*/build_to_* pattern already used by dss_to_flamo/build_to_flamo and dss_to_impz/ build_to_impz.

  • Breaking: rename the m parameter to delays in dss_to_ss and dss_to_flamo, matching every other DSS-related function.

  • Clarify docs and docstrings on the relationship between a delay state-space (DSS) system and an FDNBuild: a build is a DSS system plus fs and baked filter hooks.

  • Fix dss_to_ss raising a dimension-mismatch error for delays at the documented minimum of 3 samples.

  • Breaking: process_fdn now takes an FDNBuild and assembles a stateful td graph (new build_to_td) instead of taking raw DSS arguments; the old signature is renamed to process_dss. td operators rename filter(block)/process(signal) to process_block(block)/process_signal(signal).

0.4.2 (2026-08-27)#

  • Add the example_multislope_rir_to_fdn notebook: a measured room-transition response is fitted with two decay slopes per octave band using DecayFitNet from the multislope package, and each slope is resynthesised by its own FDN. The response it uses ships with the package as the meetingroom_to_hallway_290cm audio resource, taken from the coupled-rooms transition dataset.

  • Add nonlinear and pitch-shifting time-domain operators for shimmer reverberation – DCBlocker, ControllableFullWaveRect, SDFD, RingModulator, PitchShift and GranularPitchShift – all usable as process_dss hooks, plus the example_shimmer_fdn notebook that walks through each one inside the feedback loop of the same 8-line FDN.

  • is_uniallpass no longer solves a singular Lyapunov equation when A is itself lossless (as in the allpass-in-FDN structure). The spectral radius is checked first and such a system is reported as not uniallpass, instead of the result depending on whether LAPACK chose to warn or raise on the ill- conditioned solve.

  • Fix a device mismatch when a loss built for one run is used in another: every loss that holds a reference impulse response (MatchCumulativeEnergy, MatchEnergyDecay, MatchMagnitude, MatchImpulseResponse, MatchSpectrogram, MatchMelSpectrogram) aligned its reference once, on the first response it saw, and then handed that CPU tensor to a later CUDA step – the way a notebook cell that builds the loss but does not re-run on a runtime switch would hit it. The aligned reference is now keyed on the response’s shape, device, dtype and sample rate, and rebuilt when any of them changes. MatchSpectrogram and MatchMelSpectrogram also default their device to the response’s rather than to the CPU, so FLAMO builds its filterbanks where the model is.

0.4.1 (2026-08-24)#

  • Let fdn_build_gallery and the target-to-EQ functions optionally return the design choices used to produce their coefficients, ready to store in an FDNPreset. Build generation now also exposes the delay distribution and coprimality options and lives separately from the matrix galleries.

  • Breaking: rename the Fs parameter to fs everywhere it is still spelled with a capital – dss_to_flamo, dss_to_pr, delay_module and SDN. Every other sampling-rate argument in the package was already fs, and the odd one out forced callers to remember which spelling each function wanted. SDN also renames its fs attribute and the "fs" key of the dictionary SDN.compute() returns.

0.4.0 (2026-08-23)#

  • Add FDNPreset JSON documents: a baked FDNBuild plus catalog metadata and a controlled vocabulary for delays, matrices, and the three filter hooks. trainable_from_preset restores filter targets as meaningful FLAMO parameters only when they reproduce the baked coefficients.

  • Breaking: replace train_fdn’s mode string, and the target, criteria, sparsity_alpha and mss_nfft arguments that went with it, with a composed loss object. An objective is now written out – FlatMagnitude() + 0.2 * Sparsity(param(model, "feedback")) – and every loss is a function of the impulse response, carried as a Response, so losses own their reference data and one objective can fit two different references. pyFDN.train.objectives and build_objective are gone.

  • Breaking: collect every EQ design in pyFDN.eq (formerly pyFDN.graphicEQ) behind one EQDesign interface, with GraphicEQ, FirstOrderShelf and OnePole sharing a single implementation across the numpy and torch backends.

  • Breaking: remove absorption_filters and absorption_to_rt; the FIR absorption path they served has no callers left.

  • Breaking: name the three filter hooks post_delay, post_matrix and post_output everywhere – on FDNBuild, in the FLAMO graph, in the plots and in the JSON schema – and add the slot for the third. The build schema is version 2; version 1 files no longer load.

  • Fix colorless training on a lossless FDN, whose poles sit on the unit circle and leave |H| unbounded. build_fdn now defaults alias_decay_db from rt (LOSSLESS_ALIAS_DECAY_DB when rt is None) and trainable_from_build threads it into every module, so a magnitude objective sees a bounded response.

  • Train the decay: AttenuationFilter parametrizes the in-loop absorption filter by reverberation time per band, so the loop stays contractive for every value the parameter can take, and takes either one RT curve for the network or one per delay line. OutputEQ trains the output filter outside the recursion, the only part of an FDN that shapes the spectral envelope without touching the decay. Both are passed as the post_delay and post_output hooks of trainable_from_build.

  • Add the losses that go with it: AsymmetricFlatMagnitude, FlatSpectrogram, MatchEnergyDecay, MatchCumulativeEnergy, MatchMagnitude, MatchSpectrogram, MatchMelSpectrogram, MatchImpulseResponse, Energy, Sparsity, L1 and L2.

  • Resolve trainable parameters by name: param(model, "feedback") fails where you write it with the list of available names, and params(model) enumerates them.

  • Export the FLAMO graph builders (assemble_fdn_core, wrap_fdn_shell, gain_module, delay_module, matrix_module, fir_matrix_module, sos_filter_module, hook_module, AttenuationFilter, OutputEQ) from the top-level namespace.

  • Make build_to_impz apply all three hooks, so it no longer rejects builds that carry an output EQ, and make extract_build refuse a hook it cannot bake rather than silently dropping it.

  • Add an example notebook that fits every parameter of an FDN, decay included, to a measured concert-hall RIR, and document the loss rationale and measurements in docs/training_losses.rst.

  • Fix stereo orientation in labeled_audio, which decoded a stereo render as thousands of channels.

  • Check packaging metadata in CI and fail the documentation build on notebook cell errors.

0.3.0 (2026-08-17)#

  • Breaking: replace the pyFDN.dsp subpackage with pyFDN.td. The top-level FeedbackDelay, FIRMatrixFilter and SOSFilterBank exports are gone; use pyFDN.td operators instead.

  • Breaking: ship the packaged colorless-FDN presets as JSON rather than MATLAB .mat files.

  • Add pyFDN.td, a time-domain block-based processing graph built on NumPy alone (no torch, no FFT), with the Series, Parallel and Recursion connectors and stateful Gain, Delay, SOSBank, MatrixFIR, MatrixConvolver and TimeVaryingMatrix operators.

  • Add load_fdn_build, save_fdn_build, fdn_build_from_dict and fdn_build_to_dict for reading and writing FDN builds as JSON.

  • Add an FDN-to-FAUST example that compiles a pyFDN design with adac, and a reverberation-enhancement example.

  • Improve the example gallery and stop tracking generated documentation in the repository.

  • Test on Python 3.14 in CI and the documentation build.

0.2.0 (2026-08-10)#

  • Package compact audio examples and predefined colorless-FDN coefficients so browser-hosted tutorials work without repository-relative files.

  • Add public APIs for packaged audio, FDN presets, and paper references.

  • Add generated documentation galleries and wheel-content checks.

  • Keep decay-estimation dependencies optional for a smaller core installation.

0.1.0 (2025-07-02)#

  • First release on PyPI.