History#
0.5.0 (2026-09-28)#
Fix GPU training (#231):
model_responseexcites the model on its own device,wrap_fdn_shell/dss_to_flamo/trainable_from_buildbuild the FFT layers on the requested device, andtrain_fdnnow defaults to the model’s device instead of the CPU. Requiresflamo>=0.2.20, whose canonical module devices letdevice="cpu"/"cuda"mix with.to(...)(previouslyShellrejected them as different devices).import pyFDNno longer loads torch or flamo, which makes it about three times faster; the training API andflamo_to_prload on first use. Every public name is still exported frompyFDN.construct_cascaded_paraunitary_matrix(and thevelvet/random_densegallery types),shift_matrix_distributeandrandom_matrix_shiftare now reproducible withnp.random.seed; they used an unseeded generator before.random_orthogonaltakes an optionalrng.process_dssrenders through the same graph asdss_to_td(one time-domain engine), with identical output.dss_to_td/build_to_tdnow accept atdoperator or anyprocess_blockobject as a hook, and runpost_delayon 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)anddss_to_impz(delays, A, B, C, D, ir_len).Breaking:
pole_boundariestakes the absorption as an(sections, 6, N)SOS bank (theFDNBuild.post_delayformat) instead of an object withbandafields, and accepts a 2-D feedback matrix.Breaking:
tiny_rotation_matrixandrotation_matrix_from_anglesreturn NumPy arrays (thedtypeargument is gone) and draw from NumPy’s random state.fdn_system_galleryandfilter_matrix_galleryuse snake_case type names likefdn_matrix_gallery("nested_allpass","allpass_in_fdn","velvet", …); the old spellings are still accepted.plot_FDN_buildis nowplot_fdn_build; the old name remains an alias.Breaking: Plotly is gone; every plot function returns a Matplotlib figure, built without pyplot.
animatereturns a MatplotlibFuncAnimation(show it with.to_jshtml(); the Plotly-onlytransition_msargument is removed),SDN.visualizedraws a Matplotlib 3-D axes, and the Plotly helpersdownsampled_scatteranddownsample_plotly_traceare removed. The example notebooks use Matplotlib throughout, andplotlyis no longer in any extra.flamo_to_prno longer prints progress by default (verbose=False, likedss_to_pr).matrix_sqrtkeeps float64 precision.edcaccepts torch tensors and shares its Schroeder integral withenergy_decay_curveand the decay losses.Remove the
pyFDN.auxiliary.coupled_roomsmodule (a hand-wired FLAMO FDN used only by its test;example_coupled_roomscovers the model) and the unusedflareverbdependency.Internal:
generate/is consolidated intoorthogonal.py,paraunitary.pyandstructures.py;dss_to_flamoandtrainable_from_buildshare 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,MatchEnergyDecayandMatchCumulativeEnergyare now built on it, with unchanged values.Add the losses
SpectralFlatness(geometric over arithmetic mean of|H|, gain-invariant),MatchPhaseandMatchPhaseSpectrogram(circular phase distance, whole-response and multi-resolution STFT) andMatchMelMagnitude(mel-filterbank magnitude).Add the differentiable features
energy_decay_curve(Schroeder EDC) andmimo_rir_eigenvalues_per_frequency(eigenvalues of a square MIMO transfer matrix per frequency bin).Add the Kronecker feedback matrix of Coppola (DAFx26):
kronecker_matrixbuilds a lossless2**M x 2**Mmatrix fromMtwo-by-two rotation or reflection kernels, one angle each, andkronecker_transformapplies it inO(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 atpi/4recover the normalised Hadamard matrix, so the usual FDN mixing matrix is one point in the family. Reachable from the gallery asfdn_matrix_gallery(N, "kronecker"), withkronecker_anglesfor naming the angles to move.Add the
td.KroneckerMatrixandtd.TimeVaryingKroneckerMatrixoperators. 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 thepost_matrixhook ofprocess_dss.Add the
example_kronecker_matrixnotebook, 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 ofgain_to_geq/decay_to_geq/AttenuationFilter/OutputEQtargets is ordered onpyFDN.eq.COMMAND_FREQUENCIES. The 11-section cascade itself is unchanged.Fix the first-order shelf bilinear prewarp:
first_order_shelf_biquadusedtan(ω)rather thantan(ω/2), so a requested crossover sat at twice the named frequency. High crossovers are now clamped atfs/2.1(Nyquist-safe for the corrected prewarp) instead offs/5. The default midpoint isfs/4.example_reverberation_enhancementuses a challenge gain of 1.6.example_train_fdn_to_rirnow 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 atnfft=2**16(1.37 s) and switches to2**17(2.73 s) with FLAMO’s newShell.set_nfftbefore rendering. The step cost is linear innfft, so shorter grid reduces training time. Each training-cell run resets the grid before fitting. Requiresflamo>=0.2.18, whereset_nfftwas 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/Dand theb/c/dgains indss_to_ss) asArrayLikeinstead ofndarrayacrossdss_to_flamo,dss_to_impz,dss_to_td,dss_to_tf,dss_to_ss,general_char_poly, andloop_tf– matching what these functions already do internally (np.asarray(...)) and howdelayswas already typed. Also fixesdss_to_sssilently returning a non-arrayddwhendwas passed as a list rather than anndarray.Add
dss_to_td, the raw delay state-space (DSS) counterpart ofbuild_to_td– matching thedss_to_*/build_to_*pattern already used bydss_to_flamo/build_to_flamoanddss_to_impz/build_to_impz.Breaking: rename the
mparameter todelaysindss_to_ssanddss_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 plusfsand baked filter hooks.Fix
dss_to_ssraising a dimension-mismatch error for delays at the documented minimum of 3 samples.Breaking:
process_fdnnow takes anFDNBuildand assembles a statefultdgraph (newbuild_to_td) instead of taking raw DSS arguments; the old signature is renamed toprocess_dss.tdoperators renamefilter(block)/process(signal)toprocess_block(block)/process_signal(signal).
0.4.2 (2026-08-27)#
Add the
example_multislope_rir_to_fdnnotebook: a measured room-transition response is fitted with two decay slopes per octave band using DecayFitNet from themultislopepackage, and each slope is resynthesised by its own FDN. The response it uses ships with the package as themeetingroom_to_hallway_290cmaudio resource, taken from the coupled-rooms transition dataset.Add nonlinear and pitch-shifting time-domain operators for shimmer reverberation –
DCBlocker,ControllableFullWaveRect,SDFD,RingModulator,PitchShiftandGranularPitchShift– all usable asprocess_dsshooks, plus theexample_shimmer_fdnnotebook that walks through each one inside the feedback loop of the same 8-line FDN.is_uniallpassno longer solves a singular Lyapunov equation whenAis 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.MatchSpectrogramandMatchMelSpectrogramalso default theirdeviceto 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_galleryand the target-to-EQ functions optionally return the design choices used to produce their coefficients, ready to store in anFDNPreset. Build generation now also exposes the delay distribution and coprimality options and lives separately from the matrix galleries.Breaking: rename the
Fsparameter tofseverywhere it is still spelled with a capital –dss_to_flamo,dss_to_pr,delay_moduleandSDN. Every other sampling-rate argument in the package was alreadyfs, and the odd one out forced callers to remember which spelling each function wanted.SDNalso renames itsfsattribute and the"fs"key of the dictionarySDN.compute()returns.
0.4.0 (2026-08-23)#
Add
FDNPresetJSON documents: a bakedFDNBuildplus catalog metadata and a controlled vocabulary for delays, matrices, and the three filter hooks.trainable_from_presetrestores filter targets as meaningful FLAMO parameters only when they reproduce the baked coefficients.Breaking: replace
train_fdn’smodestring, and thetarget,criteria,sparsity_alphaandmss_nfftarguments 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 aResponse, so losses own their reference data and one objective can fit two different references.pyFDN.train.objectivesandbuild_objectiveare gone.Breaking: collect every EQ design in
pyFDN.eq(formerlypyFDN.graphicEQ) behind oneEQDesigninterface, withGraphicEQ,FirstOrderShelfandOnePolesharing a single implementation across the numpy and torch backends.Breaking: remove
absorption_filtersandabsorption_to_rt; the FIR absorption path they served has no callers left.Breaking: name the three filter hooks
post_delay,post_matrixandpost_outputeverywhere – onFDNBuild, 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_fdnnow defaultsalias_decay_dbfromrt(LOSSLESS_ALIAS_DECAY_DBwhenrtis None) andtrainable_from_buildthreads it into every module, so a magnitude objective sees a bounded response.Train the decay:
AttenuationFilterparametrizes 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.OutputEQtrains 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 thepost_delayandpost_outputhooks oftrainable_from_build.Add the losses that go with it:
AsymmetricFlatMagnitude,FlatSpectrogram,MatchEnergyDecay,MatchCumulativeEnergy,MatchMagnitude,MatchSpectrogram,MatchMelSpectrogram,MatchImpulseResponse,Energy,Sparsity,L1andL2.Resolve trainable parameters by name:
param(model, "feedback")fails where you write it with the list of available names, andparams(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_impzapply all three hooks, so it no longer rejects builds that carry an output EQ, and makeextract_buildrefuse 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.dspsubpackage withpyFDN.td. The top-levelFeedbackDelay,FIRMatrixFilterandSOSFilterBankexports are gone; usepyFDN.tdoperators instead.Breaking: ship the packaged colorless-FDN presets as JSON rather than MATLAB
.matfiles.Add
pyFDN.td, a time-domain block-based processing graph built on NumPy alone (no torch, no FFT), with theSeries,ParallelandRecursionconnectors and statefulGain,Delay,SOSBank,MatrixFIR,MatrixConvolverandTimeVaryingMatrixoperators.Add
load_fdn_build,save_fdn_build,fdn_build_from_dictandfdn_build_to_dictfor 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.