pyFDN 0.4.0__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyfdn-0.4.0 → pyfdn-0.4.2}/HISTORY.rst +51 -2
- {pyfdn-0.4.0 → pyfdn-0.4.2}/PKG-INFO +5 -4
- {pyfdn-0.4.0 → pyfdn-0.4.2}/README.rst +4 -4
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/api_reference.rst +34 -20
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/example_gallery.py +7 -4
- pyfdn-0.4.2/docs/usage.rst +102 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/pyproject.toml +2 -2
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/__init__.py +47 -32
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/acoustics.py +2 -9
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/allpass.py +26 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/flamo.py +8 -345
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/flamo_graph.py +2 -2
- pyfdn-0.4.0/src/pyFDN/build_io.py → pyfdn-0.4.2/src/pyFDN/build.py +50 -25
- pyfdn-0.4.2/src/pyFDN/eq/__init__.py +49 -0
- pyfdn-0.4.2/src/pyFDN/eq/_design_record.py +25 -0
- pyfdn-0.4.2/src/pyFDN/eq/biquads.py +120 -0
- pyfdn-0.4.2/src/pyFDN/eq/design.py +235 -0
- pyfdn-0.4.2/src/pyFDN/eq/graphic_eq.py +194 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/SDN.py +15 -15
- pyfdn-0.4.2/src/pyFDN/generate/fdn_build_gallery.py +305 -0
- pyfdn-0.4.2/src/pyFDN/generate/fdn_matrix_gallery.py +341 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/sample_delay_lengths.py +9 -4
- pyfdn-0.4.2/src/pyFDN/preset.py +195 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/ATTRIBUTION.md +11 -2
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/audio/metadata.json +11 -0
- pyfdn-0.4.2/src/pyFDN/resources/audio/rir/meetingroom_to_hallway_290cm.wav +0 -0
- pyfdn-0.4.2/src/pyFDN/resources/licenses/coupled-rooms-CC-BY-4.0.txt +413 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_N16_d1.json +412 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_N16_d2.json +412 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_N4_d1.json +88 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_N4_d2.json +88 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_N6_d1.json +122 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_N6_d2.json +122 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_N8_d1.json +164 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_N8_d2.json +164 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N16_d1.json +412 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N16_d2.json +412 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N4_d1.json +88 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N4_d2.json +88 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N6_d1.json +122 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N6_d2.json +122 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N8_d1.json +164 -0
- pyfdn-0.4.2/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N8_d2.json +164 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/references.bib +10 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/td/__init__.py +12 -0
- pyfdn-0.4.2/src/pyFDN/td/operators.py +1028 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/__init__.py +6 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/build.py +154 -24
- pyfdn-0.4.2/src/pyFDN/train/filters.py +304 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/losses/_targets.py +22 -4
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/losses/spectral.py +16 -4
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/losses/temporal.py +10 -4
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/params.py +2 -2
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/dss_to_flamo.py +6 -6
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/dss_to_impz.py +1 -1
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/dss_to_pr.py +2 -2
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN.egg-info/PKG-INFO +5 -4
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN.egg-info/SOURCES.txt +12 -10
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_api_reference.py +21 -0
- pyfdn-0.4.2/tests/test_auxiliary_allpass.py +36 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_auxiliary_flamo.py +4 -4
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_auxiliary_plot.py +3 -3
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_auxiliary_utils.py +6 -10
- pyfdn-0.4.0/tests/test_build_io.py → pyfdn-0.4.2/tests/test_build.py +3 -3
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_dss_to_pr.py +1 -1
- pyfdn-0.4.2/tests/test_eq_designs.py +392 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_flamo_one_pole_absorption.py +2 -2
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_flamo_to_pr.py +5 -5
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_generate.py +87 -15
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_packaged_resources.py +11 -5
- pyfdn-0.4.2/tests/test_preset.py +298 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_process_extensions.py +4 -5
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_td_graph_processing.py +1 -1
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_td_operators.py +232 -1
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_train.py +152 -65
- pyfdn-0.4.0/docs/usage.rst +0 -39
- pyfdn-0.4.0/src/pyFDN/eq/__init__.py +0 -45
- pyfdn-0.4.0/src/pyFDN/eq/absorption_geq.py +0 -52
- pyfdn-0.4.0/src/pyFDN/eq/bandpass_filter.py +0 -42
- pyfdn-0.4.0/src/pyFDN/eq/design_geq.py +0 -175
- pyfdn-0.4.0/src/pyFDN/eq/designs.py +0 -177
- pyfdn-0.4.0/src/pyFDN/eq/first_order.py +0 -168
- pyfdn-0.4.0/src/pyFDN/eq/graphic_eq.py +0 -83
- pyfdn-0.4.0/src/pyFDN/eq/one_pole.py +0 -76
- pyfdn-0.4.0/src/pyFDN/eq/shelving_filter.py +0 -64
- pyfdn-0.4.0/src/pyFDN/generate/fdn_matrix_gallery.py +0 -599
- pyfdn-0.4.0/src/pyFDN/presets.py +0 -50
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_N16_d1.json +0 -396
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_N16_d2.json +0 -396
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_N4_d1.json +0 -72
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_N4_d2.json +0 -72
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_N6_d1.json +0 -106
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_N6_d2.json +0 -106
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_N8_d1.json +0 -148
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_N8_d2.json +0 -148
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N16_d1.json +0 -396
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N16_d2.json +0 -396
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N4_d1.json +0 -72
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N4_d2.json +0 -72
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N6_d1.json +0 -106
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N6_d2.json +0 -106
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N8_d1.json +0 -148
- pyfdn-0.4.0/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N8_d2.json +0 -148
- pyfdn-0.4.0/src/pyFDN/td/operators.py +0 -508
- pyfdn-0.4.0/tests/test_eq_designs.py +0 -289
- {pyfdn-0.4.0 → pyfdn-0.4.2}/AUTHORS.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/CONTRIBUTING.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/LICENSE +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/MANIFEST.in +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/Makefile +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/__init__.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/audio_gallery.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/authors.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/conf.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/contributing.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/history.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/index.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/installation.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/logo/logo_pyFDN_3.png +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/logo/logo_pyFDN_4.png +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/logo/pyfdn_logo_basic.png +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/logo/pyfdn_logo_wave.png +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/make.bat +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/patch_rst.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/readme.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/references.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/docs/training_losses.rst +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/setup.cfg +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/setup.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/__init__.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/audio.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/coupled_rooms.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/delay.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/marimo_utils.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/math.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/plot.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/poles.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/tiny_rotation_matrix.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/auxiliary/utils.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/eq/_backend.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/eq/probe_sos.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/allpass_FDN/__init__.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/allpass_FDN/allpass_completion.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/allpass_FDN/homogeneous_allpass_fdn.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/allpass_FDN/rand_admissible_homogeneous_allpass.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/allpass_in_fdn.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/anderson_matrix.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/complete_orthogonal.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/construct_cascaded_paraunitary_matrix.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/construct_paraunitary_from_elementals.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/construct_velvet_feedback_matrix.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/degree_one_lossless.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/householder_matrix.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/is_almost_zero.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/nearest_orthogonal.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/nearest_sign_agnostic_orthogonal.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/random_matrix_shift.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/random_orthogonal.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/schroeder_reverberator.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/shift_matrix.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/generate/shift_matrix_distribute.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/process.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/references.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/__init__.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/audio/drums/drums.wav +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/audio/general/synth_dry.wav +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/audio/rir/s3_r4_o.wav +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/audio/speech/P1_Set1_8.wav +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/audio/speech/P20_Set1_8.wav +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/audio/strings/Kleiderschrank_Taylor_DI.wav +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/audio/strings/Sommerhit2016_Taylor_DI.wav +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/resources/licenses/diff-fdn-colorless-MIT.txt +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/td/connectors.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/engine.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/losses/__init__.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/losses/base.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/losses/parameter.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/train/response.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/dss_to_ss.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/dss_to_tf.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/flamo_to_pr.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/impz_to_res.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/mtf_to_impz.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN/translate/pr_to_impz.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN.egg-info/dependency_links.txt +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN.egg-info/requires.txt +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/src/pyFDN.egg-info/top_level.txt +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/__init__.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/conftest.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/matloader.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/reference/README.md +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/reference/example_onePoleAbsorption.mat +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/reference/onePoleAbsorption_reference.mat +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_audio_gallery.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_auxiliary_acoustics.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_auxiliary_delay.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_auxiliary_math.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_coupled_rooms.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_example_gallery.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_flamo_graph.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_marimo_examples_run.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_pyFDN.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_sdn.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_td_connectors.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_time_varying_matrix.py +0 -0
- {pyfdn-0.4.0 → pyfdn-0.4.2}/tests/test_translate.py +0 -0
|
@@ -2,9 +2,58 @@
|
|
|
2
2
|
History
|
|
3
3
|
=======
|
|
4
4
|
|
|
5
|
+
0.4.2 (2026-08-27)
|
|
6
|
+
------------------
|
|
7
|
+
|
|
8
|
+
* Add the ``example_multislope_rir_to_fdn`` notebook: a measured room-transition
|
|
9
|
+
response is fitted with two decay slopes per octave band using DecayFitNet
|
|
10
|
+
from the ``multislope`` package, and each slope is resynthesised by its own
|
|
11
|
+
FDN. The response it uses ships with the package as the
|
|
12
|
+
``meetingroom_to_hallway_290cm`` audio resource, taken from the coupled-rooms
|
|
13
|
+
transition dataset.
|
|
14
|
+
* Add nonlinear and pitch-shifting time-domain operators for shimmer
|
|
15
|
+
reverberation -- ``DCBlocker``, ``ControllableFullWaveRect``, ``SDFD``,
|
|
16
|
+
``RingModulator``, ``PitchShift`` and ``GranularPitchShift`` -- all usable as
|
|
17
|
+
``process_fdn`` hooks, plus the ``example_shimmer_fdn`` notebook that walks
|
|
18
|
+
through each one inside the feedback loop of the same 8-line FDN.
|
|
19
|
+
* ``is_uniallpass`` no longer solves a singular Lyapunov equation when ``A`` is
|
|
20
|
+
itself lossless (as in the allpass-in-FDN structure). The spectral radius is
|
|
21
|
+
checked first and such a system is reported as not uniallpass, instead of the
|
|
22
|
+
result depending on whether LAPACK chose to warn or raise on the ill-
|
|
23
|
+
conditioned solve.
|
|
24
|
+
* Fix a device mismatch when a loss built for one run is used in another: every
|
|
25
|
+
loss that holds a reference impulse response (``MatchCumulativeEnergy``,
|
|
26
|
+
``MatchEnergyDecay``, ``MatchMagnitude``, ``MatchImpulseResponse``,
|
|
27
|
+
``MatchSpectrogram``, ``MatchMelSpectrogram``) aligned its reference once, on
|
|
28
|
+
the first response it saw, and then handed that CPU tensor to a later CUDA
|
|
29
|
+
step -- the way a notebook cell that builds the loss but does not re-run on a
|
|
30
|
+
runtime switch would hit it. The aligned reference is now keyed on the
|
|
31
|
+
response's shape, device, dtype and sample rate, and rebuilt when any of them
|
|
32
|
+
changes. ``MatchSpectrogram`` and ``MatchMelSpectrogram`` also default their
|
|
33
|
+
``device`` to the response's rather than to the CPU, so FLAMO builds its
|
|
34
|
+
filterbanks where the model is.
|
|
35
|
+
|
|
36
|
+
0.4.1 (2026-08-24)
|
|
37
|
+
------------------
|
|
38
|
+
|
|
39
|
+
* Let ``fdn_build_gallery`` and the target-to-EQ functions optionally return
|
|
40
|
+
the design choices used to produce their coefficients, ready to store in an
|
|
41
|
+
``FDNPreset``. Build generation now also exposes the delay distribution and
|
|
42
|
+
coprimality options and lives separately from the matrix galleries.
|
|
43
|
+
* **Breaking:** rename the ``Fs`` parameter to ``fs`` everywhere it is still
|
|
44
|
+
spelled with a capital -- ``dss_to_flamo``, ``dss_to_pr``, ``delay_module``
|
|
45
|
+
and ``SDN``. Every other sampling-rate argument in the package was already
|
|
46
|
+
``fs``, and the odd one out forced callers to remember which spelling each
|
|
47
|
+
function wanted. ``SDN`` also renames its ``fs`` attribute and the ``"fs"``
|
|
48
|
+
key of the dictionary ``SDN.compute()`` returns.
|
|
49
|
+
|
|
5
50
|
0.4.0 (2026-08-23)
|
|
6
51
|
------------------
|
|
7
52
|
|
|
53
|
+
* Add ``FDNPreset`` JSON documents: a baked ``FDNBuild`` plus catalog
|
|
54
|
+
metadata and a controlled vocabulary for delays, matrices, and the three
|
|
55
|
+
filter hooks. ``trainable_from_preset`` restores filter targets as meaningful
|
|
56
|
+
FLAMO parameters only when they reproduce the baked coefficients.
|
|
8
57
|
* **Breaking:** replace ``train_fdn``'s ``mode`` string, and the ``target``,
|
|
9
58
|
``criteria``, ``sparsity_alpha`` and ``mss_nfft`` arguments that went with
|
|
10
59
|
it, with a composed loss object. An objective is now written out --
|
|
@@ -27,7 +76,7 @@ History
|
|
|
27
76
|
from ``rt`` (``LOSSLESS_ALIAS_DECAY_DB`` when ``rt`` is None) and
|
|
28
77
|
``trainable_from_build`` threads it into every module, so a magnitude
|
|
29
78
|
objective sees a bounded response.
|
|
30
|
-
* Train the decay: ``
|
|
79
|
+
* Train the decay: ``AttenuationFilter`` parametrizes the in-loop absorption filter
|
|
31
80
|
by reverberation time per band, so the loop stays contractive for every value
|
|
32
81
|
the parameter can take, and takes either one RT curve for the network or one
|
|
33
82
|
per delay line. ``OutputEQ`` trains the output filter outside the recursion,
|
|
@@ -43,7 +92,7 @@ History
|
|
|
43
92
|
enumerates them.
|
|
44
93
|
* Export the FLAMO graph builders (``assemble_fdn_core``, ``wrap_fdn_shell``,
|
|
45
94
|
``gain_module``, ``delay_module``, ``matrix_module``, ``fir_matrix_module``,
|
|
46
|
-
``sos_filter_module``, ``hook_module``, ``
|
|
95
|
+
``sos_filter_module``, ``hook_module``, ``AttenuationFilter``, ``OutputEQ``) from
|
|
47
96
|
the top-level namespace.
|
|
48
97
|
* Make ``build_to_impz`` apply all three hooks, so it no longer rejects builds
|
|
49
98
|
that carry an output EQ, and make ``extract_build`` refuse a hook it cannot
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyFDN
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Python library for Feedback Delay Networks
|
|
5
5
|
Author: Sebastian J. Schlecht, Facundo Franchino, Jeremy Bai
|
|
6
6
|
Maintainer: Facundo Franchino, Sebastian J. Schlecht
|
|
@@ -17,6 +17,7 @@ Requires-Python: >=3.10
|
|
|
17
17
|
Description-Content-Type: text/x-rst
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
License-File: src/pyFDN/resources/ATTRIBUTION.md
|
|
20
|
+
License-File: src/pyFDN/resources/licenses/coupled-rooms-CC-BY-4.0.txt
|
|
20
21
|
License-File: src/pyFDN/resources/licenses/diff-fdn-colorless-MIT.txt
|
|
21
22
|
Requires-Dist: numpy
|
|
22
23
|
Requires-Dist: soundfile
|
|
@@ -148,17 +149,17 @@ All main functions are accessible directly from the top-level ``pyFDN`` namespac
|
|
|
148
149
|
feedback = pyFDN.random_orthogonal(len(delays))
|
|
149
150
|
|
|
150
151
|
# one-pole absorption filters targeting RT of 1.2 s at DC and 0.9 s at Nyquist
|
|
151
|
-
absorption = pyFDN.
|
|
152
|
+
absorption = pyFDN.decay_to_one_pole(1.2, 0.9, delays, fs)
|
|
152
153
|
|
|
153
154
|
# convert delay state-space to standard state-space (A_ss, b, c, d)
|
|
154
155
|
A_ss, b, c, d = pyFDN.dss_to_ss(delays, feedback)
|
|
155
156
|
|
|
156
157
|
Alternatively, import specific functions directly::
|
|
157
158
|
|
|
158
|
-
from pyFDN import
|
|
159
|
+
from pyFDN import decay_to_one_pole, lin_to_db, random_orthogonal
|
|
159
160
|
|
|
160
161
|
feedback = random_orthogonal(4)
|
|
161
|
-
absorption =
|
|
162
|
+
absorption = decay_to_one_pole(1.2, 0.9, [100, 150, 200, 250], 48_000)
|
|
162
163
|
|
|
163
164
|
|
|
164
165
|
Development
|
|
@@ -78,17 +78,17 @@ All main functions are accessible directly from the top-level ``pyFDN`` namespac
|
|
|
78
78
|
feedback = pyFDN.random_orthogonal(len(delays))
|
|
79
79
|
|
|
80
80
|
# one-pole absorption filters targeting RT of 1.2 s at DC and 0.9 s at Nyquist
|
|
81
|
-
absorption = pyFDN.
|
|
81
|
+
absorption = pyFDN.decay_to_one_pole(1.2, 0.9, delays, fs)
|
|
82
82
|
|
|
83
83
|
# convert delay state-space to standard state-space (A_ss, b, c, d)
|
|
84
84
|
A_ss, b, c, d = pyFDN.dss_to_ss(delays, feedback)
|
|
85
85
|
|
|
86
86
|
Alternatively, import specific functions directly::
|
|
87
87
|
|
|
88
|
-
from pyFDN import
|
|
88
|
+
from pyFDN import decay_to_one_pole, lin_to_db, random_orthogonal
|
|
89
89
|
|
|
90
90
|
feedback = random_orthogonal(4)
|
|
91
|
-
absorption =
|
|
91
|
+
absorption = decay_to_one_pole(1.2, 0.9, [100, 150, 200, 250], 48_000)
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
Development
|
|
@@ -112,4 +112,4 @@ Helpful links
|
|
|
112
112
|
* `List of papers on Feedback Delay Networks <https://github.com/gdalsanto/delay-network-reverbs>`_ .
|
|
113
113
|
* `Multislope Estimation library <https://github.com/artificial-audio/multislope>`_ .
|
|
114
114
|
* `FLAMO (An Open-Source Library for Frequency-Domain Differentiable Audio Processing) <https://github.com/gdalsanto/flamo>`_ .
|
|
115
|
-
* `ADAC (Automatic Differentiable Audio Compilation) library <https://github.com/cucuwritescode/adac>`_ .
|
|
115
|
+
* `ADAC (Automatic Differentiable Audio Compilation) library <https://github.com/cucuwritescode/adac>`_ .
|
|
@@ -95,34 +95,36 @@ Acoustics & Absorption
|
|
|
95
95
|
pyFDN.slope_amplitude_to_level
|
|
96
96
|
pyFDN.slope_to_rt
|
|
97
97
|
|
|
98
|
-
EQ
|
|
99
|
-
|
|
98
|
+
EQ Design (``pyFDN.eq``)
|
|
99
|
+
-------------------------
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
Explicit functions map either decay targets or gain targets onto a named
|
|
102
|
+
filter design. The same functions run in NumPy or Torch; the trainable
|
|
103
|
+
:class:`pyFDN.AttenuationFilter` and :class:`pyFDN.OutputEQ` modules use these
|
|
104
|
+
mappings inside a training loop. ``EQDesign`` is the literal choice of
|
|
105
|
+
``"graphic_eq"``, ``"first_order_shelf"``, or ``"one_pole"`` used by those
|
|
106
|
+
modules. The target-to-EQ functions accept ``return_design=True`` when their
|
|
107
|
+
JSON-compatible design record is also needed for an ``FDNPreset``.
|
|
106
108
|
|
|
107
109
|
.. autosummary::
|
|
108
110
|
:toctree: generated/
|
|
109
111
|
:nosignatures:
|
|
110
112
|
|
|
111
113
|
pyFDN.EQDesign
|
|
112
|
-
pyFDN.
|
|
113
|
-
pyFDN.
|
|
114
|
-
pyFDN.
|
|
115
|
-
pyFDN.
|
|
116
|
-
pyFDN.
|
|
114
|
+
pyFDN.decay_to_geq
|
|
115
|
+
pyFDN.decay_to_first_order_shelf
|
|
116
|
+
pyFDN.decay_to_one_pole
|
|
117
|
+
pyFDN.gain_to_geq
|
|
118
|
+
pyFDN.gain_to_bounded_geq
|
|
119
|
+
pyFDN.gain_to_first_order_shelf
|
|
120
|
+
pyFDN.gain_to_one_pole
|
|
117
121
|
pyFDN.geq_design_matrix
|
|
118
|
-
pyFDN.
|
|
119
|
-
pyFDN.
|
|
120
|
-
pyFDN.
|
|
121
|
-
pyFDN.
|
|
122
|
-
pyFDN.
|
|
122
|
+
pyFDN.lowshelf_biquad
|
|
123
|
+
pyFDN.highshelf_biquad
|
|
124
|
+
pyFDN.peaking_biquad
|
|
125
|
+
pyFDN.first_order_shelf_biquad
|
|
126
|
+
pyFDN.one_pole_biquad
|
|
123
127
|
pyFDN.probe_sos
|
|
124
|
-
pyFDN.shelving_filter
|
|
125
|
-
pyFDN.bandpass_filter
|
|
126
128
|
|
|
127
129
|
Time-Domain Graph (``pyFDN.td``)
|
|
128
130
|
--------------------------------
|
|
@@ -139,6 +141,12 @@ rendered with ``.process(signal)``. See :mod:`pyFDN.td`.
|
|
|
139
141
|
pyFDN.td.Gain
|
|
140
142
|
pyFDN.td.Delay
|
|
141
143
|
pyFDN.td.AbsoluteValue
|
|
144
|
+
pyFDN.td.DCBlocker
|
|
145
|
+
pyFDN.td.ControllableFullWaveRect
|
|
146
|
+
pyFDN.td.SDFD
|
|
147
|
+
pyFDN.td.RingModulator
|
|
148
|
+
pyFDN.td.PitchShift
|
|
149
|
+
pyFDN.td.GranularPitchShift
|
|
142
150
|
pyFDN.td.SOSBank
|
|
143
151
|
pyFDN.td.MatrixFIR
|
|
144
152
|
pyFDN.td.MatrixConvolver
|
|
@@ -181,7 +189,7 @@ An FDN as FLAMO modules, assembled from numpy values. The three filter hooks --
|
|
|
181
189
|
pyFDN.fir_matrix_module
|
|
182
190
|
pyFDN.sos_filter_module
|
|
183
191
|
pyFDN.hook_module
|
|
184
|
-
pyFDN.
|
|
192
|
+
pyFDN.AttenuationFilter
|
|
185
193
|
pyFDN.OutputEQ
|
|
186
194
|
|
|
187
195
|
Polynomial & Matrix Maths
|
|
@@ -245,6 +253,11 @@ Build Files, Packaged Examples & References
|
|
|
245
253
|
pyFDN.audio_metadata
|
|
246
254
|
pyFDN.load_audio
|
|
247
255
|
pyFDN.available_fdn_presets
|
|
256
|
+
pyFDN.get_fdn_preset
|
|
257
|
+
pyFDN.FDNPreset
|
|
258
|
+
pyFDN.fdn_preset_to_dict
|
|
259
|
+
pyFDN.fdn_preset_from_dict
|
|
260
|
+
pyFDN.save_fdn_preset
|
|
248
261
|
pyFDN.load_fdn_preset
|
|
249
262
|
pyFDN.fdn_build_to_dict
|
|
250
263
|
pyFDN.fdn_build_from_dict
|
|
@@ -294,6 +307,7 @@ Training
|
|
|
294
307
|
|
|
295
308
|
pyFDN.build_fdn
|
|
296
309
|
pyFDN.trainable_from_build
|
|
310
|
+
pyFDN.trainable_from_preset
|
|
297
311
|
pyFDN.build_set_decay
|
|
298
312
|
pyFDN.Trainable
|
|
299
313
|
pyFDN.train_fdn
|
|
@@ -15,11 +15,14 @@ OUTPUT_FILE = DOCS_DIR / "examples_gallery.rst"
|
|
|
15
15
|
|
|
16
16
|
CATEGORY_ORDER = (
|
|
17
17
|
"Getting Started",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
18
|
+
"Feedback Matrices",
|
|
19
|
+
"Absorption & Decay",
|
|
20
|
+
"Analysis & Verification",
|
|
21
|
+
"Optimization",
|
|
22
|
+
"Allpass FDNs",
|
|
21
23
|
"Special FDNs",
|
|
22
|
-
"
|
|
24
|
+
"Representations",
|
|
25
|
+
"Export & Deployment",
|
|
23
26
|
)
|
|
24
27
|
|
|
25
28
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
=====
|
|
2
|
+
Usage
|
|
3
|
+
=====
|
|
4
|
+
|
|
5
|
+
All main functions are accessible directly from ``pyFDN``::
|
|
6
|
+
|
|
7
|
+
import pyFDN
|
|
8
|
+
|
|
9
|
+
feedback = pyFDN.random_orthogonal(4)
|
|
10
|
+
attenuation = pyFDN.decay_to_first_order_shelf(
|
|
11
|
+
1.2, 0.9, None, [100, 150, 200, 250], 48_000
|
|
12
|
+
)
|
|
13
|
+
gain_db = pyFDN.lin_to_db([0.5, 1.0, 2.0])
|
|
14
|
+
|
|
15
|
+
Or import specific functions::
|
|
16
|
+
|
|
17
|
+
from pyFDN import random_orthogonal, decay_to_first_order_shelf, dss_to_ss
|
|
18
|
+
|
|
19
|
+
feedback = random_orthogonal(4)
|
|
20
|
+
|
|
21
|
+
Packaged tutorial resources
|
|
22
|
+
---------------------------
|
|
23
|
+
|
|
24
|
+
The small resources used by the browser tutorials are available through the
|
|
25
|
+
public API, independent of the current working directory::
|
|
26
|
+
|
|
27
|
+
dry, fs = pyFDN.load_audio("synth_dry")
|
|
28
|
+
|
|
29
|
+
preset = pyFDN.get_fdn_preset("colorless_N8_d1")
|
|
30
|
+
reverberator = pyFDN.build_set_decay(preset.build, 1.5)
|
|
31
|
+
|
|
32
|
+
citation = pyFDN.paper_link("Allpass_Feedback_Delay_Networks")
|
|
33
|
+
|
|
34
|
+
Use ``pyFDN.available_audio()`` and ``pyFDN.available_fdn_presets()`` to list
|
|
35
|
+
the bundled choices. Attribution and license information for audio is returned
|
|
36
|
+
by ``pyFDN.audio_metadata(name)``.
|
|
37
|
+
|
|
38
|
+
FDN builds can also be exchanged as readable, versioned JSON files::
|
|
39
|
+
|
|
40
|
+
pyFDN.save_fdn_build("reverberator.json", reverberator)
|
|
41
|
+
restored = pyFDN.load_fdn_build("reverberator.json")
|
|
42
|
+
|
|
43
|
+
Preset documents
|
|
44
|
+
----------------
|
|
45
|
+
|
|
46
|
+
An ``FDNPreset`` keeps a baked ``FDNBuild`` together with catalog metadata and
|
|
47
|
+
the design choices that cannot be recovered reliably from its numbers. Unknown
|
|
48
|
+
design choices are left out rather than guessed. Generators and EQ design
|
|
49
|
+
functions return only their numerical result by default; opt into their design
|
|
50
|
+
record when preparing a preset::
|
|
51
|
+
|
|
52
|
+
build, design = pyFDN.fdn_build_gallery(
|
|
53
|
+
N=8,
|
|
54
|
+
fs=48_000,
|
|
55
|
+
delay_distribution="geometric",
|
|
56
|
+
coprime=True,
|
|
57
|
+
rt=1.2,
|
|
58
|
+
rt_nyquist=0.8,
|
|
59
|
+
return_design=True,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
A separately designed filter can return the same kind of record. The caller
|
|
63
|
+
only has to say which FDN hook receives it::
|
|
64
|
+
|
|
65
|
+
import dataclasses
|
|
66
|
+
|
|
67
|
+
post_matrix, post_matrix_design = pyFDN.gain_to_one_pole(
|
|
68
|
+
gain_db=[0.0] * 8,
|
|
69
|
+
gain_db_nyquist=[-3.0] * 8,
|
|
70
|
+
return_design=True,
|
|
71
|
+
)
|
|
72
|
+
build = dataclasses.replace(build, post_matrix=post_matrix)
|
|
73
|
+
design["post_matrix"] = post_matrix_design
|
|
74
|
+
|
|
75
|
+
Once all numerical and design parts are assembled, freeze that particular
|
|
76
|
+
realization as the preset::
|
|
77
|
+
|
|
78
|
+
preset = pyFDN.FDNPreset(
|
|
79
|
+
build=build,
|
|
80
|
+
metadata={
|
|
81
|
+
"name": "small-room",
|
|
82
|
+
"description": "A short, neutral room",
|
|
83
|
+
"authors": ["A. Author"],
|
|
84
|
+
"license": "CC0-1.0",
|
|
85
|
+
"tags": ["room", "short"],
|
|
86
|
+
},
|
|
87
|
+
design=design,
|
|
88
|
+
)
|
|
89
|
+
pyFDN.save_fdn_preset("small-room.json", preset)
|
|
90
|
+
restored = pyFDN.load_fdn_preset("small-room.json")
|
|
91
|
+
|
|
92
|
+
Metadata is an open dictionary because it is descriptive rather than part of
|
|
93
|
+
the sound. By convention, ``tags`` is a list of strings, so selecting presets
|
|
94
|
+
does not require a metadata class::
|
|
95
|
+
|
|
96
|
+
requested = {"room", "short"}
|
|
97
|
+
matches = requested <= set(restored.metadata.get("tags", []))
|
|
98
|
+
|
|
99
|
+
The numerical build, including its sample rate, is authoritative. Filter design
|
|
100
|
+
records may additionally carry RT or gain targets. In that case
|
|
101
|
+
``pyFDN.trainable_from_preset`` restores the meaningful FLAMO parameters and
|
|
102
|
+
checks that they reproduce the baked SOS coefficients before building a model.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pyFDN"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.2"
|
|
8
8
|
description = "Python library for Feedback Delay Networks"
|
|
9
9
|
readme = "README.rst"
|
|
10
10
|
authors = [
|
|
@@ -113,7 +113,7 @@ include = ["pyFDN*"]
|
|
|
113
113
|
# triggers on. Usage: bump-my-version bump {major|minor|patch}
|
|
114
114
|
|
|
115
115
|
[tool.bumpversion]
|
|
116
|
-
current_version = "0.4.
|
|
116
|
+
current_version = "0.4.2"
|
|
117
117
|
allow_dirty = false
|
|
118
118
|
commit = true
|
|
119
119
|
message = "Bump version: {current_version} → {new_version}"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from importlib import import_module
|
|
4
4
|
|
|
5
5
|
__author__ = "Facundo Franchino"
|
|
6
|
-
__version__ = "0.4.
|
|
6
|
+
__version__ = "0.4.2"
|
|
7
7
|
|
|
8
8
|
__all__ = [
|
|
9
9
|
# acoustics
|
|
@@ -11,11 +11,8 @@ __all__ = [
|
|
|
11
11
|
"estimate_initial_level_bands",
|
|
12
12
|
"estimate_rt_bands",
|
|
13
13
|
"edc",
|
|
14
|
-
"first_order_absorption",
|
|
15
|
-
"first_order_shelving_eq",
|
|
16
14
|
"octave_band_filterbank",
|
|
17
15
|
"octave_bands",
|
|
18
|
-
"one_pole_absorption",
|
|
19
16
|
"rt_to_gain_per_sample",
|
|
20
17
|
"rt_to_slope",
|
|
21
18
|
"slope_amplitude_to_level",
|
|
@@ -39,7 +36,7 @@ __all__ = [
|
|
|
39
36
|
"fir_matrix_module",
|
|
40
37
|
"sos_filter_module",
|
|
41
38
|
"hook_module",
|
|
42
|
-
"
|
|
39
|
+
"AttenuationFilter",
|
|
43
40
|
"OutputEQ",
|
|
44
41
|
"audio_metadata",
|
|
45
42
|
"available_audio",
|
|
@@ -48,7 +45,12 @@ __all__ = [
|
|
|
48
45
|
"paper_link",
|
|
49
46
|
"paper_reference",
|
|
50
47
|
"available_fdn_presets",
|
|
48
|
+
"get_fdn_preset",
|
|
51
49
|
"load_fdn_preset",
|
|
50
|
+
"FDNPreset",
|
|
51
|
+
"fdn_preset_from_dict",
|
|
52
|
+
"fdn_preset_to_dict",
|
|
53
|
+
"save_fdn_preset",
|
|
52
54
|
"fdn_build_from_dict",
|
|
53
55
|
"fdn_build_to_dict",
|
|
54
56
|
"load_fdn_build",
|
|
@@ -80,18 +82,21 @@ __all__ = [
|
|
|
80
82
|
"shift_matrix_distribute",
|
|
81
83
|
"tiny_rotation_matrix",
|
|
82
84
|
# eq
|
|
83
|
-
"absorption_geq",
|
|
84
|
-
"bandpass_filter",
|
|
85
85
|
"EQDesign",
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
86
|
+
"decay_to_first_order_shelf",
|
|
87
|
+
"decay_to_geq",
|
|
88
|
+
"decay_to_one_pole",
|
|
89
|
+
"first_order_shelf_biquad",
|
|
90
|
+
"gain_to_bounded_geq",
|
|
91
|
+
"gain_to_first_order_shelf",
|
|
92
|
+
"gain_to_geq",
|
|
93
|
+
"gain_to_one_pole",
|
|
90
94
|
"geq_design_matrix",
|
|
91
|
-
"
|
|
92
|
-
"
|
|
95
|
+
"highshelf_biquad",
|
|
96
|
+
"lowshelf_biquad",
|
|
97
|
+
"one_pole_biquad",
|
|
98
|
+
"peaking_biquad",
|
|
93
99
|
"probe_sos",
|
|
94
|
-
"shelving_filter",
|
|
95
100
|
# polynomial and matrix maths
|
|
96
101
|
"adj_poly",
|
|
97
102
|
"adjugate",
|
|
@@ -148,6 +153,7 @@ __all__ = [
|
|
|
148
153
|
# training
|
|
149
154
|
"build_fdn",
|
|
150
155
|
"trainable_from_build",
|
|
156
|
+
"trainable_from_preset",
|
|
151
157
|
"LOSSLESS_ALIAS_DECAY_DB",
|
|
152
158
|
"build_set_decay",
|
|
153
159
|
"Trainable",
|
|
@@ -263,8 +269,6 @@ from .auxiliary.delay import (
|
|
|
263
269
|
swap_flamo_recursion_paths,
|
|
264
270
|
)
|
|
265
271
|
from .auxiliary.flamo import (
|
|
266
|
-
DecayFilter,
|
|
267
|
-
OutputEQ,
|
|
268
272
|
assemble_fdn_core,
|
|
269
273
|
delay_module,
|
|
270
274
|
fir_matrix_module,
|
|
@@ -350,7 +354,8 @@ from .auxiliary.utils import (
|
|
|
350
354
|
skew,
|
|
351
355
|
sq_to_db,
|
|
352
356
|
)
|
|
353
|
-
from .
|
|
357
|
+
from .build import (
|
|
358
|
+
FDNBuild,
|
|
354
359
|
fdn_build_from_dict,
|
|
355
360
|
fdn_build_to_dict,
|
|
356
361
|
load_fdn_build,
|
|
@@ -358,20 +363,20 @@ from .build_io import (
|
|
|
358
363
|
)
|
|
359
364
|
from .eq import (
|
|
360
365
|
EQDesign,
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
366
|
+
decay_to_first_order_shelf,
|
|
367
|
+
decay_to_geq,
|
|
368
|
+
decay_to_one_pole,
|
|
369
|
+
first_order_shelf_biquad,
|
|
370
|
+
gain_to_bounded_geq,
|
|
371
|
+
gain_to_first_order_shelf,
|
|
372
|
+
gain_to_geq,
|
|
373
|
+
gain_to_one_pole,
|
|
369
374
|
geq_design_matrix,
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
375
|
+
highshelf_biquad,
|
|
376
|
+
lowshelf_biquad,
|
|
377
|
+
one_pole_biquad,
|
|
378
|
+
peaking_biquad,
|
|
373
379
|
probe_sos,
|
|
374
|
-
shelving_filter,
|
|
375
380
|
)
|
|
376
381
|
from .generate.allpass_FDN import allpass_completion
|
|
377
382
|
from .generate.allpass_FDN.allpass_completion import (
|
|
@@ -405,10 +410,9 @@ from .generate.construct_paraunitary_from_elementals import (
|
|
|
405
410
|
)
|
|
406
411
|
from .generate.construct_velvet_feedback_matrix import construct_velvet_feedback_matrix
|
|
407
412
|
from .generate.degree_one_lossless import degree_one_lossless
|
|
413
|
+
from .generate.fdn_build_gallery import fdn_build_gallery
|
|
408
414
|
from .generate.fdn_matrix_gallery import (
|
|
409
|
-
FDNBuild,
|
|
410
415
|
FDNSystem,
|
|
411
|
-
fdn_build_gallery,
|
|
412
416
|
fdn_matrix_gallery,
|
|
413
417
|
fdn_system_gallery,
|
|
414
418
|
filter_matrix_gallery,
|
|
@@ -426,7 +430,15 @@ from .generate.schroeder_reverberator import schroeder_reverberator
|
|
|
426
430
|
from .generate.SDN import SDN
|
|
427
431
|
from .generate.shift_matrix import shift_matrix
|
|
428
432
|
from .generate.shift_matrix_distribute import shift_matrix_distribute
|
|
429
|
-
from .
|
|
433
|
+
from .preset import (
|
|
434
|
+
FDNPreset,
|
|
435
|
+
available_fdn_presets,
|
|
436
|
+
fdn_preset_from_dict,
|
|
437
|
+
fdn_preset_to_dict,
|
|
438
|
+
get_fdn_preset,
|
|
439
|
+
load_fdn_preset,
|
|
440
|
+
save_fdn_preset,
|
|
441
|
+
)
|
|
430
442
|
|
|
431
443
|
# fdn processing
|
|
432
444
|
from .process import process_fdn
|
|
@@ -438,6 +450,7 @@ from .train import (
|
|
|
438
450
|
L2,
|
|
439
451
|
LOSSLESS_ALIAS_DECAY_DB,
|
|
440
452
|
AsymmetricFlatMagnitude,
|
|
453
|
+
AttenuationFilter,
|
|
441
454
|
Energy,
|
|
442
455
|
FlatMagnitude,
|
|
443
456
|
FlatSpectrogram,
|
|
@@ -448,6 +461,7 @@ from .train import (
|
|
|
448
461
|
MatchMagnitude,
|
|
449
462
|
MatchMelSpectrogram,
|
|
450
463
|
MatchSpectrogram,
|
|
464
|
+
OutputEQ,
|
|
451
465
|
ParameterLoss,
|
|
452
466
|
ParamRef,
|
|
453
467
|
Response,
|
|
@@ -463,6 +477,7 @@ from .train import (
|
|
|
463
477
|
params,
|
|
464
478
|
train_fdn,
|
|
465
479
|
trainable_from_build,
|
|
480
|
+
trainable_from_preset,
|
|
466
481
|
)
|
|
467
482
|
|
|
468
483
|
# state-space translators
|
|
@@ -9,14 +9,6 @@ from numpy.typing import ArrayLike
|
|
|
9
9
|
from scipy.signal import sosfreqz
|
|
10
10
|
from scipy.special import erfc
|
|
11
11
|
|
|
12
|
-
# The filter designs live in pyFDN.eq, and are re-exported here because this
|
|
13
|
-
# module's rt_to_slope is what turns a reverberation time into the dB target
|
|
14
|
-
# they take. They import it inside a function, not at module level, so the two
|
|
15
|
-
# modules do not cycle.
|
|
16
|
-
from pyFDN.eq.first_order import first_order_absorption as first_order_absorption
|
|
17
|
-
from pyFDN.eq.first_order import first_order_shelving_eq as first_order_shelving_eq
|
|
18
|
-
from pyFDN.eq.one_pole import one_pole_absorption as one_pole_absorption
|
|
19
|
-
|
|
20
12
|
|
|
21
13
|
def rt_to_slope(rt: ArrayLike, fs: float) -> np.ndarray:
|
|
22
14
|
"""Convert reverb time (RT, seconds) to energy decay slope (dB per sample)."""
|
|
@@ -457,7 +449,8 @@ def sos_gain_per_sample_curves(
|
|
|
457
449
|
----------
|
|
458
450
|
sos : (n_sections, 6, N) array
|
|
459
451
|
Per-channel SOS bank; section rows are ``[b0, b1, b2, a0, a1, a2]``. Same
|
|
460
|
-
format as :func:`
|
|
452
|
+
format as :func:`pyFDN.decay_to_one_pole` /
|
|
453
|
+
:func:`pyFDN.decay_to_first_order_shelf`
|
|
461
454
|
return.
|
|
462
455
|
delays : (N,) array-like
|
|
463
456
|
Delay lengths in samples, one per channel. Used to scale gain to per-sample.
|
|
@@ -15,6 +15,10 @@ from scipy.linalg import solve_discrete_lyapunov
|
|
|
15
15
|
from pyFDN.auxiliary.math import general_char_poly
|
|
16
16
|
from pyFDN.generate.is_almost_zero import is_almost_zero
|
|
17
17
|
|
|
18
|
+
# How far inside the unit circle the eigenvalues of A must sit for the discrete
|
|
19
|
+
# Lyapunov equation solved by is_uniallpass to be well posed.
|
|
20
|
+
_STABILITY_TOL = 1e-9
|
|
21
|
+
|
|
18
22
|
|
|
19
23
|
def poletti_allpass(
|
|
20
24
|
g: float, U: np.ndarray
|
|
@@ -72,11 +76,33 @@ def is_uniallpass(
|
|
|
72
76
|
True if the system is uniallpass.
|
|
73
77
|
P : ndarray
|
|
74
78
|
Solution of discrete Lyapunov A P A' - P + B B' = 0; diagonal if uniallpass.
|
|
79
|
+
All-NaN when A is not strictly stable, see the note below.
|
|
80
|
+
|
|
81
|
+
Notes
|
|
82
|
+
-----
|
|
83
|
+
The Lyapunov equation only has a (unique, finite) solution when A is
|
|
84
|
+
strictly stable. If A itself is lossless -- as in the allpass-in-FDN
|
|
85
|
+
structure, where the feedback matrix has all its eigenvalues on the unit
|
|
86
|
+
circle -- no such P exists, and the linear system scipy solves is exactly
|
|
87
|
+
singular. Rather than let that surface as an ill-conditioned solve (which
|
|
88
|
+
raises or returns garbage depending on the LAPACK build), the spectral
|
|
89
|
+
radius is checked up front and the system reported as not uniallpass.
|
|
75
90
|
"""
|
|
76
91
|
A = np.asarray(A, dtype=float)
|
|
77
92
|
B = np.asarray(B, dtype=float)
|
|
78
93
|
C = np.asarray(C, dtype=float)
|
|
79
94
|
D = np.asarray(D, dtype=float)
|
|
95
|
+
# P exists only for a strictly stable A; on the unit circle the Lyapunov
|
|
96
|
+
# operator P -> A P A' - P is singular (eigenvalue pairs with λi·λj = 1).
|
|
97
|
+
spectral_radius = float(np.max(np.abs(np.linalg.eigvals(A)))) if A.size else 0.0
|
|
98
|
+
if spectral_radius >= 1.0 - _STABILITY_TOL:
|
|
99
|
+
warnings.warn(
|
|
100
|
+
f"A has spectral radius {spectral_radius:.6g} >= 1; the discrete "
|
|
101
|
+
"Lyapunov equation has no finite solution, so the system is not "
|
|
102
|
+
"uniallpass.",
|
|
103
|
+
stacklevel=2,
|
|
104
|
+
)
|
|
105
|
+
return False, np.full_like(A, np.nan)
|
|
80
106
|
# P = dlyap(A, B @ B')
|
|
81
107
|
P = solve_discrete_lyapunov(A, B @ B.T)
|
|
82
108
|
# Check P is diagonal
|