pyFDN 0.3.0__tar.gz → 0.4.1__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.
Files changed (183) hide show
  1. {pyfdn-0.3.0 → pyfdn-0.4.1}/CONTRIBUTING.rst +4 -4
  2. pyfdn-0.4.1/HISTORY.rst +101 -0
  3. {pyfdn-0.3.0 → pyfdn-0.4.1}/PKG-INFO +4 -4
  4. {pyfdn-0.3.0 → pyfdn-0.4.1}/README.rst +4 -4
  5. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/api_reference.rst +78 -12
  6. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/conf.py +42 -3
  7. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/example_gallery.py +7 -4
  8. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/index.rst +1 -0
  9. pyfdn-0.4.1/docs/training_losses.rst +99 -0
  10. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/usage.rst +4 -2
  11. {pyfdn-0.3.0 → pyfdn-0.4.1}/pyproject.toml +2 -2
  12. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/__init__.py +107 -26
  13. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/__init__.py +2 -2
  14. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/acoustics.py +3 -211
  15. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/coupled_rooms.py +5 -5
  16. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/flamo.py +178 -60
  17. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/flamo_graph.py +59 -24
  18. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/marimo_utils.py +25 -2
  19. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/plot.py +43 -30
  20. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/utils.py +1 -1
  21. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/build_io.py +45 -20
  22. pyfdn-0.4.1/src/pyFDN/eq/__init__.py +47 -0
  23. pyfdn-0.4.1/src/pyFDN/eq/_backend.py +34 -0
  24. pyfdn-0.4.1/src/pyFDN/eq/biquads.py +120 -0
  25. pyfdn-0.4.1/src/pyFDN/eq/design.py +176 -0
  26. pyfdn-0.4.1/src/pyFDN/eq/graphic_eq.py +187 -0
  27. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/SDN.py +15 -15
  28. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/fdn_matrix_gallery.py +70 -31
  29. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/process.py +1 -1
  30. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_N16_d1.json +4 -3
  31. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_N16_d2.json +4 -3
  32. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_N4_d1.json +4 -3
  33. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_N4_d2.json +4 -3
  34. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_N6_d1.json +4 -3
  35. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_N6_d2.json +4 -3
  36. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_N8_d1.json +4 -3
  37. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_N8_d2.json +4 -3
  38. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N16_d1.json +4 -3
  39. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N16_d2.json +4 -3
  40. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N4_d1.json +4 -3
  41. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N4_d2.json +4 -3
  42. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N6_d1.json +4 -3
  43. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N6_d2.json +4 -3
  44. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N8_d1.json +4 -3
  45. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/presets/colorless_FDN/colorless_init_N8_d2.json +4 -3
  46. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/td/operators.py +2 -2
  47. pyfdn-0.4.1/src/pyFDN/train/__init__.py +88 -0
  48. pyfdn-0.4.1/src/pyFDN/train/build.py +463 -0
  49. pyfdn-0.4.1/src/pyFDN/train/engine.py +207 -0
  50. pyfdn-0.4.1/src/pyFDN/train/filters.py +249 -0
  51. pyfdn-0.4.1/src/pyFDN/train/losses/__init__.py +46 -0
  52. pyfdn-0.4.1/src/pyFDN/train/losses/_targets.py +63 -0
  53. pyfdn-0.4.1/src/pyFDN/train/losses/base.py +151 -0
  54. pyfdn-0.4.1/src/pyFDN/train/losses/parameter.py +66 -0
  55. pyfdn-0.4.1/src/pyFDN/train/losses/spectral.py +356 -0
  56. pyfdn-0.4.1/src/pyFDN/train/losses/temporal.py +347 -0
  57. pyfdn-0.4.1/src/pyFDN/train/params.py +152 -0
  58. pyfdn-0.4.1/src/pyFDN/train/response.py +148 -0
  59. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/dss_to_flamo.py +59 -45
  60. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/dss_to_impz.py +17 -21
  61. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/dss_to_pr.py +2 -2
  62. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/impz_to_res.py +1 -1
  63. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN.egg-info/PKG-INFO +4 -4
  64. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN.egg-info/SOURCES.txt +17 -9
  65. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_api_reference.py +26 -0
  66. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_auxiliary_acoustics.py +0 -61
  67. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_auxiliary_flamo.py +7 -14
  68. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_auxiliary_plot.py +35 -14
  69. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_auxiliary_utils.py +45 -11
  70. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_build_io.py +14 -4
  71. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_dss_to_pr.py +1 -1
  72. pyfdn-0.4.1/tests/test_eq_designs.py +352 -0
  73. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_flamo_graph.py +4 -4
  74. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_flamo_one_pole_absorption.py +2 -2
  75. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_flamo_to_pr.py +6 -6
  76. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_generate.py +26 -23
  77. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_process_extensions.py +54 -13
  78. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_td_graph_processing.py +1 -1
  79. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_td_operators.py +1 -1
  80. pyfdn-0.4.1/tests/test_train.py +1448 -0
  81. pyfdn-0.3.0/HISTORY.rst +0 -37
  82. pyfdn-0.3.0/src/pyFDN/graphicEQ/__init__.py +0 -17
  83. pyfdn-0.3.0/src/pyFDN/graphicEQ/absorption_geq.py +0 -54
  84. pyfdn-0.3.0/src/pyFDN/graphicEQ/bandpass_filter.py +0 -34
  85. pyfdn-0.3.0/src/pyFDN/graphicEQ/design_geq.py +0 -73
  86. pyfdn-0.3.0/src/pyFDN/graphicEQ/graphic_eq.py +0 -74
  87. pyfdn-0.3.0/src/pyFDN/graphicEQ/shelving_filter.py +0 -55
  88. pyfdn-0.3.0/src/pyFDN/train/__init__.py +0 -35
  89. pyfdn-0.3.0/src/pyFDN/train/build.py +0 -321
  90. pyfdn-0.3.0/src/pyFDN/train/engine.py +0 -182
  91. pyfdn-0.3.0/src/pyFDN/train/objectives.py +0 -207
  92. pyfdn-0.3.0/tests/test_graphic_eq.py +0 -129
  93. pyfdn-0.3.0/tests/test_train.py +0 -269
  94. {pyfdn-0.3.0 → pyfdn-0.4.1}/AUTHORS.rst +0 -0
  95. {pyfdn-0.3.0 → pyfdn-0.4.1}/LICENSE +0 -0
  96. {pyfdn-0.3.0 → pyfdn-0.4.1}/MANIFEST.in +0 -0
  97. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/Makefile +0 -0
  98. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/__init__.py +0 -0
  99. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/audio_gallery.py +0 -0
  100. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/authors.rst +0 -0
  101. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/contributing.rst +0 -0
  102. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/history.rst +0 -0
  103. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/installation.rst +0 -0
  104. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/logo/logo_pyFDN_3.png +0 -0
  105. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/logo/logo_pyFDN_4.png +0 -0
  106. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/logo/pyfdn_logo_basic.png +0 -0
  107. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/logo/pyfdn_logo_wave.png +0 -0
  108. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/make.bat +0 -0
  109. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/patch_rst.py +0 -0
  110. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/readme.rst +0 -0
  111. {pyfdn-0.3.0 → pyfdn-0.4.1}/docs/references.py +0 -0
  112. {pyfdn-0.3.0 → pyfdn-0.4.1}/setup.cfg +0 -0
  113. {pyfdn-0.3.0 → pyfdn-0.4.1}/setup.py +0 -0
  114. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/allpass.py +0 -0
  115. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/audio.py +0 -0
  116. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/delay.py +0 -0
  117. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/math.py +0 -0
  118. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/poles.py +0 -0
  119. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/auxiliary/tiny_rotation_matrix.py +0 -0
  120. {pyfdn-0.3.0/src/pyFDN/graphicEQ → pyfdn-0.4.1/src/pyFDN/eq}/probe_sos.py +0 -0
  121. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/allpass_FDN/__init__.py +0 -0
  122. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/allpass_FDN/allpass_completion.py +0 -0
  123. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/allpass_FDN/homogeneous_allpass_fdn.py +0 -0
  124. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/allpass_FDN/rand_admissible_homogeneous_allpass.py +0 -0
  125. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/allpass_in_fdn.py +0 -0
  126. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/anderson_matrix.py +0 -0
  127. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/complete_orthogonal.py +0 -0
  128. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/construct_cascaded_paraunitary_matrix.py +0 -0
  129. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/construct_paraunitary_from_elementals.py +0 -0
  130. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/construct_velvet_feedback_matrix.py +0 -0
  131. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/degree_one_lossless.py +0 -0
  132. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/householder_matrix.py +0 -0
  133. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/is_almost_zero.py +0 -0
  134. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/nearest_orthogonal.py +0 -0
  135. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/nearest_sign_agnostic_orthogonal.py +0 -0
  136. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/random_matrix_shift.py +0 -0
  137. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/random_orthogonal.py +0 -0
  138. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/sample_delay_lengths.py +0 -0
  139. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/schroeder_reverberator.py +0 -0
  140. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/shift_matrix.py +0 -0
  141. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/generate/shift_matrix_distribute.py +0 -0
  142. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/presets.py +0 -0
  143. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/references.py +0 -0
  144. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/ATTRIBUTION.md +0 -0
  145. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/__init__.py +0 -0
  146. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/audio/drums/drums.wav +0 -0
  147. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/audio/general/synth_dry.wav +0 -0
  148. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/audio/metadata.json +0 -0
  149. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/audio/rir/s3_r4_o.wav +0 -0
  150. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/audio/speech/P1_Set1_8.wav +0 -0
  151. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/audio/speech/P20_Set1_8.wav +0 -0
  152. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/audio/strings/Kleiderschrank_Taylor_DI.wav +0 -0
  153. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/audio/strings/Sommerhit2016_Taylor_DI.wav +0 -0
  154. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/licenses/diff-fdn-colorless-MIT.txt +0 -0
  155. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/resources/references.bib +0 -0
  156. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/td/__init__.py +0 -0
  157. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/td/connectors.py +0 -0
  158. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/dss_to_ss.py +0 -0
  159. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/dss_to_tf.py +0 -0
  160. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/flamo_to_pr.py +0 -0
  161. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/mtf_to_impz.py +0 -0
  162. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN/translate/pr_to_impz.py +0 -0
  163. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN.egg-info/dependency_links.txt +0 -0
  164. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN.egg-info/requires.txt +0 -0
  165. {pyfdn-0.3.0 → pyfdn-0.4.1}/src/pyFDN.egg-info/top_level.txt +0 -0
  166. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/__init__.py +0 -0
  167. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/conftest.py +0 -0
  168. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/matloader.py +0 -0
  169. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/reference/README.md +0 -0
  170. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/reference/example_onePoleAbsorption.mat +0 -0
  171. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/reference/onePoleAbsorption_reference.mat +0 -0
  172. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_audio_gallery.py +0 -0
  173. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_auxiliary_delay.py +0 -0
  174. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_auxiliary_math.py +0 -0
  175. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_coupled_rooms.py +0 -0
  176. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_example_gallery.py +0 -0
  177. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_marimo_examples_run.py +0 -0
  178. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_packaged_resources.py +0 -0
  179. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_pyFDN.py +0 -0
  180. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_sdn.py +0 -0
  181. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_td_connectors.py +0 -0
  182. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_time_varying_matrix.py +0 -0
  183. {pyfdn-0.3.0 → pyfdn-0.4.1}/tests/test_translate.py +0 -0
@@ -150,11 +150,11 @@ documentation sources, and tests:
150
150
  time-domain graph. ``process_fdn`` uses ``MatrixFIR`` for polynomial feedback
151
151
  matrices; ``SOSBank`` implements per-delay-line filter cascades used for
152
152
  frequency-dependent absorption.
153
- * ``src/pyFDN/graphicEQ/`` contains graphic-EQ and absorption-filter design,
154
- while ``src/pyFDN/translate/`` converts between delay state-space, transfer
153
+ * ``src/pyFDN/eq/`` contains every EQ and absorption-filter design, while
154
+ ``src/pyFDN/translate/`` converts between delay state-space, transfer
155
155
  function, pole-residue, impulse-response, and FLAMO representations.
156
- * ``src/pyFDN/train/`` contains the trainable FDN construction, objectives,
157
- and optimization loop. ``src/pyFDN/auxiliary/`` holds shared analysis,
156
+ * ``src/pyFDN/train/`` contains the trainable FDN construction, the composable
157
+ losses in ``train/losses/``, and the optimization loop. ``src/pyFDN/auxiliary/`` holds shared analysis,
158
158
  plotting, audio, delay, and numerical helpers.
159
159
  * ``examples/`` contains executable Marimo notebooks. Metadata at the top of
160
160
  each ``example_*.py`` file drives the generated documentation gallery.
@@ -0,0 +1,101 @@
1
+ =======
2
+ History
3
+ =======
4
+
5
+ 0.4.1 (2026-08-24)
6
+ ------------------
7
+
8
+ * **Breaking:** rename the ``Fs`` parameter to ``fs`` everywhere it is still
9
+ spelled with a capital -- ``dss_to_flamo``, ``dss_to_pr``, ``delay_module``
10
+ and ``SDN``. Every other sampling-rate argument in the package was already
11
+ ``fs``, and the odd one out forced callers to remember which spelling each
12
+ function wanted. ``SDN`` also renames its ``fs`` attribute and the ``"fs"``
13
+ key of the dictionary ``SDN.compute()`` returns.
14
+
15
+ 0.4.0 (2026-08-23)
16
+ ------------------
17
+
18
+ * **Breaking:** replace ``train_fdn``'s ``mode`` string, and the ``target``,
19
+ ``criteria``, ``sparsity_alpha`` and ``mss_nfft`` arguments that went with
20
+ it, with a composed loss object. An objective is now written out --
21
+ ``FlatMagnitude() + 0.2 * Sparsity(param(model, "feedback"))`` -- and every
22
+ loss is a function of the impulse response, carried as a ``Response``, so
23
+ losses own their reference data and one objective can fit two different
24
+ references. ``pyFDN.train.objectives`` and ``build_objective`` are gone.
25
+ * **Breaking:** collect every EQ design in ``pyFDN.eq`` (formerly
26
+ ``pyFDN.graphicEQ``) behind one ``EQDesign`` interface, with ``GraphicEQ``,
27
+ ``FirstOrderShelf`` and ``OnePole`` sharing a single implementation across
28
+ the numpy and torch backends.
29
+ * **Breaking:** remove ``absorption_filters`` and ``absorption_to_rt``; the FIR
30
+ absorption path they served has no callers left.
31
+ * **Breaking:** name the three filter hooks ``post_delay``, ``post_matrix`` and
32
+ ``post_output`` everywhere -- on ``FDNBuild``, in the FLAMO graph, in the
33
+ plots and in the JSON schema -- and add the slot for the third. The build
34
+ schema is version 2; version 1 files no longer load.
35
+ * Fix colorless training on a lossless FDN, whose poles sit on the unit circle
36
+ and leave ``|H|`` unbounded. ``build_fdn`` now defaults ``alias_decay_db``
37
+ from ``rt`` (``LOSSLESS_ALIAS_DECAY_DB`` when ``rt`` is None) and
38
+ ``trainable_from_build`` threads it into every module, so a magnitude
39
+ objective sees a bounded response.
40
+ * Train the decay: ``DecayFilter`` parametrizes the in-loop absorption filter
41
+ by reverberation time per band, so the loop stays contractive for every value
42
+ the parameter can take, and takes either one RT curve for the network or one
43
+ per delay line. ``OutputEQ`` trains the output filter outside the recursion,
44
+ the only part of an FDN that shapes the spectral envelope without touching
45
+ the decay. Both are passed as the ``post_delay`` and ``post_output`` hooks of
46
+ ``trainable_from_build``.
47
+ * Add the losses that go with it: ``AsymmetricFlatMagnitude``,
48
+ ``FlatSpectrogram``, ``MatchEnergyDecay``, ``MatchCumulativeEnergy``,
49
+ ``MatchMagnitude``, ``MatchSpectrogram``, ``MatchMelSpectrogram``,
50
+ ``MatchImpulseResponse``, ``Energy``, ``Sparsity``, ``L1`` and ``L2``.
51
+ * Resolve trainable parameters by name: ``param(model, "feedback")`` fails
52
+ where you write it with the list of available names, and ``params(model)``
53
+ enumerates them.
54
+ * Export the FLAMO graph builders (``assemble_fdn_core``, ``wrap_fdn_shell``,
55
+ ``gain_module``, ``delay_module``, ``matrix_module``, ``fir_matrix_module``,
56
+ ``sos_filter_module``, ``hook_module``, ``DecayFilter``, ``OutputEQ``) from
57
+ the top-level namespace.
58
+ * Make ``build_to_impz`` apply all three hooks, so it no longer rejects builds
59
+ that carry an output EQ, and make ``extract_build`` refuse a hook it cannot
60
+ bake rather than silently dropping it.
61
+ * Add an example notebook that fits every parameter of an FDN, decay included,
62
+ to a measured concert-hall RIR, and document the loss rationale and
63
+ measurements in ``docs/training_losses.rst``.
64
+ * Fix stereo orientation in ``labeled_audio``, which decoded a stereo render as
65
+ thousands of channels.
66
+ * Check packaging metadata in CI and fail the documentation build on notebook
67
+ cell errors.
68
+
69
+ 0.3.0 (2026-08-17)
70
+ ------------------
71
+
72
+ * **Breaking:** replace the ``pyFDN.dsp`` subpackage with ``pyFDN.td``. The
73
+ top-level ``FeedbackDelay``, ``FIRMatrixFilter`` and ``SOSFilterBank``
74
+ exports are gone; use ``pyFDN.td`` operators instead.
75
+ * **Breaking:** ship the packaged colorless-FDN presets as JSON rather than
76
+ MATLAB ``.mat`` files.
77
+ * Add ``pyFDN.td``, a time-domain block-based processing graph built on NumPy
78
+ alone (no torch, no FFT), with the ``Series``, ``Parallel`` and
79
+ ``Recursion`` connectors and stateful ``Gain``, ``Delay``, ``SOSBank``,
80
+ ``MatrixFIR``, ``MatrixConvolver`` and ``TimeVaryingMatrix`` operators.
81
+ * Add ``load_fdn_build``, ``save_fdn_build``, ``fdn_build_from_dict`` and
82
+ ``fdn_build_to_dict`` for reading and writing FDN builds as JSON.
83
+ * Add an FDN-to-FAUST example that compiles a pyFDN design with adac, and a
84
+ reverberation-enhancement example.
85
+ * Improve the example gallery and stop tracking generated documentation in the
86
+ repository.
87
+ * Test on Python 3.14 in CI and the documentation build.
88
+
89
+ 0.2.0 (2026-08-10)
90
+ ------------------
91
+
92
+ * Package compact audio examples and predefined colorless-FDN coefficients so
93
+ browser-hosted tutorials work without repository-relative files.
94
+ * Add public APIs for packaged audio, FDN presets, and paper references.
95
+ * Add generated documentation galleries and wheel-content checks.
96
+ * Keep decay-estimation dependencies optional for a smaller core installation.
97
+
98
+ 0.1.0 (2025-07-02)
99
+ ------------------
100
+
101
+ * First release on PyPI.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyFDN
3
- Version: 0.3.0
3
+ Version: 0.4.1
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
@@ -148,17 +148,17 @@ All main functions are accessible directly from the top-level ``pyFDN`` namespac
148
148
  feedback = pyFDN.random_orthogonal(len(delays))
149
149
 
150
150
  # one-pole absorption filters targeting RT of 1.2 s at DC and 0.9 s at Nyquist
151
- absorption = pyFDN.one_pole_absorption(1.2, 0.9, delays, fs)
151
+ absorption = pyFDN.decay_to_one_pole(1.2, 0.9, delays, fs)
152
152
 
153
153
  # convert delay state-space to standard state-space (A_ss, b, c, d)
154
154
  A_ss, b, c, d = pyFDN.dss_to_ss(delays, feedback)
155
155
 
156
156
  Alternatively, import specific functions directly::
157
157
 
158
- from pyFDN import random_orthogonal, one_pole_absorption, lin_to_db
158
+ from pyFDN import decay_to_one_pole, lin_to_db, random_orthogonal
159
159
 
160
160
  feedback = random_orthogonal(4)
161
- absorption = one_pole_absorption(1.2, 0.9, [100, 150, 200, 250], 48_000)
161
+ absorption = decay_to_one_pole(1.2, 0.9, [100, 150, 200, 250], 48_000)
162
162
 
163
163
 
164
164
  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.one_pole_absorption(1.2, 0.9, delays, fs)
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 random_orthogonal, one_pole_absorption, lin_to_db
88
+ from pyFDN import decay_to_one_pole, lin_to_db, random_orthogonal
89
89
 
90
90
  feedback = random_orthogonal(4)
91
- absorption = one_pole_absorption(1.2, 0.9, [100, 150, 200, 250], 48_000)
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>`_ .
@@ -83,14 +83,9 @@ Acoustics & Absorption
83
83
  :toctree: generated/
84
84
  :nosignatures:
85
85
 
86
- pyFDN.absorption_filters
87
- pyFDN.first_order_absorption
88
- pyFDN.first_order_shelving_eq
89
- pyFDN.one_pole_absorption
90
86
  pyFDN.sos_gain_per_sample_curves
91
87
  pyFDN.echo_density
92
88
  pyFDN.edc
93
- pyFDN.absorption_to_rt
94
89
  pyFDN.estimate_initial_level_bands
95
90
  pyFDN.estimate_rt_bands
96
91
  pyFDN.octave_bands
@@ -100,19 +95,35 @@ Acoustics & Absorption
100
95
  pyFDN.slope_amplitude_to_level
101
96
  pyFDN.slope_to_rt
102
97
 
103
- Graphic EQ
104
- ----------
98
+ EQ Design (``pyFDN.eq``)
99
+ -------------------------
100
+
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.DecayFilter` 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.
105
107
 
106
108
  .. autosummary::
107
109
  :toctree: generated/
108
110
  :nosignatures:
109
111
 
110
- pyFDN.design_geq
111
- pyFDN.graphic_eq
112
- pyFDN.absorption_geq
112
+ pyFDN.EQDesign
113
+ pyFDN.decay_to_geq
114
+ pyFDN.decay_to_first_order_shelf
115
+ pyFDN.decay_to_one_pole
116
+ pyFDN.gain_to_geq
117
+ pyFDN.gain_to_bounded_geq
118
+ pyFDN.gain_to_first_order_shelf
119
+ pyFDN.gain_to_one_pole
120
+ pyFDN.geq_design_matrix
121
+ pyFDN.lowshelf_biquad
122
+ pyFDN.highshelf_biquad
123
+ pyFDN.peaking_biquad
124
+ pyFDN.first_order_shelf_biquad
125
+ pyFDN.one_pole_biquad
113
126
  pyFDN.probe_sos
114
- pyFDN.shelving_filter
115
- pyFDN.bandpass_filter
116
127
 
117
128
  Time-Domain Graph (``pyFDN.td``)
118
129
  --------------------------------
@@ -151,6 +162,29 @@ Delay Utilities
151
162
  pyFDN.flamo_time_response
152
163
  pyFDN.flamo_freq_response
153
164
 
165
+ Building a FLAMO Graph
166
+ ----------------------
167
+
168
+ An FDN as FLAMO modules, assembled from numpy values. The three filter hooks --
169
+ ``post_delay`` inside the loop, ``post_matrix`` on the feedback path,
170
+ ``post_output`` on the wet signal -- are the same three
171
+ :func:`pyFDN.process_fdn` takes, in the same positions and under the same names.
172
+
173
+ .. autosummary::
174
+ :toctree: generated/
175
+ :nosignatures:
176
+
177
+ pyFDN.assemble_fdn_core
178
+ pyFDN.wrap_fdn_shell
179
+ pyFDN.gain_module
180
+ pyFDN.delay_module
181
+ pyFDN.matrix_module
182
+ pyFDN.fir_matrix_module
183
+ pyFDN.sos_filter_module
184
+ pyFDN.hook_module
185
+ pyFDN.DecayFilter
186
+ pyFDN.OutputEQ
187
+
154
188
  Polynomial & Matrix Maths
155
189
  --------------------------
156
190
 
@@ -265,6 +299,38 @@ Training
265
299
  pyFDN.Trainable
266
300
  pyFDN.train_fdn
267
301
  pyFDN.TrainLog
302
+ pyFDN.LOSSLESS_ALIAS_DECAY_DB
303
+
304
+ Training Objectives
305
+ -------------------
306
+
307
+ An objective is a weighted sum of losses, composed with ``+`` and ``*``. Losses
308
+ on the impulse response read a :class:`pyFDN.Response`; losses on a model
309
+ parameter take a :class:`pyFDN.ParamRef` from :func:`pyFDN.param`.
310
+
311
+ .. autosummary::
312
+ :toctree: generated/
313
+ :nosignatures:
314
+
315
+ pyFDN.Response
316
+ pyFDN.model_response
317
+ pyFDN.param
318
+ pyFDN.params
319
+ pyFDN.ParamRef
320
+ pyFDN.Loss
321
+ pyFDN.FlatMagnitude
322
+ pyFDN.AsymmetricFlatMagnitude
323
+ pyFDN.FlatSpectrogram
324
+ pyFDN.MatchMagnitude
325
+ pyFDN.MatchSpectrogram
326
+ pyFDN.MatchMelSpectrogram
327
+ pyFDN.MatchImpulseResponse
328
+ pyFDN.MatchEnergyDecay
329
+ pyFDN.MatchCumulativeEnergy
330
+ pyFDN.Energy
331
+ pyFDN.Sparsity
332
+ pyFDN.L1
333
+ pyFDN.L2
268
334
 
269
335
  Plotting
270
336
  --------
@@ -148,6 +148,17 @@ marimo_cache_notebooks = False
148
148
  #
149
149
  # This patch lives in conf.py (our repo), so the installed sphinx-marimo package
150
150
  # stays pristine and deployment (RTD / GitHub Actions) needs no vendored changes.
151
+ #
152
+ # Cell errors are build failures: a notebook that raises still produces HTML,
153
+ # with the traceback baked in where the output should be, so a broken example
154
+ # reaches the published site looking like a rendered page. We record every
155
+ # notebook whose export exited non-zero and fail the build at the end (see
156
+ # ``setup`` below) instead of aborting on the first one, so a single run reports
157
+ # all of them. Set ``PYFDN_DOCS_ALLOW_NOTEBOOK_ERRORS=1`` to downgrade this back
158
+ # to a warning when you need a build out of a knowingly broken notebook.
159
+ _marimo_export_failures: "list[tuple[str, str]]" = []
160
+
161
+
151
162
  def _patch_marimo_static_export():
152
163
  import subprocess
153
164
 
@@ -173,8 +184,8 @@ def _patch_marimo_static_export():
173
184
  # `html` (not `html-wasm`) executes the notebook server-side with the real
174
185
  # venv and embeds the outputs. marimo returns a non-zero exit code when any
175
186
  # cell raises during execution, but it still writes the HTML (with the error
176
- # baked in), so we log a warning and keep going rather than aborting the
177
- # whole docs build on one bad notebook.
187
+ # baked in), so we record the failure and keep going; the build-finished
188
+ # handler turns the collected failures into a build error.
178
189
  proc = subprocess.run(
179
190
  [
180
191
  "marimo",
@@ -190,9 +201,10 @@ def _patch_marimo_static_export():
190
201
  )
191
202
  if proc.returncode != 0:
192
203
  print(
193
- f"[conf.py] WARNING: '{relative_path}' had cell errors during static "
204
+ f"[conf.py] ERROR: '{relative_path}' had cell errors during static "
194
205
  f"export (output still written):\n{proc.stderr.strip()}"
195
206
  )
207
+ _marimo_export_failures.append((str(relative_path), proc.stderr.strip()))
196
208
 
197
209
  return {
198
210
  "name": output_name,
@@ -205,3 +217,30 @@ def _patch_marimo_static_export():
205
217
 
206
218
 
207
219
  _patch_marimo_static_export()
220
+
221
+
222
+ def _fail_on_marimo_export_errors(app, exception):
223
+ """Fail the build if any notebook raised while being exported."""
224
+ # The build already failed for another reason; don't mask it.
225
+ if exception is not None or not _marimo_export_failures:
226
+ return
227
+
228
+ report = "\n\n".join(
229
+ f"{path}:\n{stderr}" for path, stderr in _marimo_export_failures
230
+ )
231
+ if os.environ.get("PYFDN_DOCS_ALLOW_NOTEBOOK_ERRORS") == "1":
232
+ print(
233
+ f"[conf.py] WARNING: {len(_marimo_export_failures)} notebook(s) had cell "
234
+ f"errors; failing is disabled via PYFDN_DOCS_ALLOW_NOTEBOOK_ERRORS:\n{report}"
235
+ )
236
+ return
237
+
238
+ raise RuntimeError(
239
+ f"{len(_marimo_export_failures)} example notebook(s) raised during static "
240
+ f"export. The generated HTML contains the traceback instead of the intended "
241
+ f"output, so this must not be published:\n\n{report}"
242
+ )
243
+
244
+
245
+ def setup(app):
246
+ app.connect("build-finished", _fail_on_marimo_export_errors)
@@ -15,11 +15,14 @@ OUTPUT_FILE = DOCS_DIR / "examples_gallery.rst"
15
15
 
16
16
  CATEGORY_ORDER = (
17
17
  "Getting Started",
18
- "Absorption & Filters",
19
- "Translation Examples",
20
- "Allpass FDN Examples",
18
+ "Feedback Matrices",
19
+ "Absorption & Decay",
20
+ "Analysis & Verification",
21
+ "Optimization",
22
+ "Allpass FDNs",
21
23
  "Special FDNs",
22
- "FDN Design & Analysis",
24
+ "Representations",
25
+ "Export & Deployment",
23
26
  )
24
27
 
25
28
 
@@ -58,6 +58,7 @@ feedback matrices, designing loop filters, and inspecting pole locations.
58
58
  usage
59
59
  examples_gallery
60
60
  api_reference
61
+ training_losses
61
62
  modules
62
63
  contributing
63
64
  authors
@@ -0,0 +1,99 @@
1
+ ===============================
2
+ Training losses: design notes
3
+ ===============================
4
+
5
+ Why the losses in :mod:`pyFDN.train.losses` are shaped the way they are. The
6
+ reasoning is qualitative on purpose: what is stated here is a design choice and
7
+ its rationale, not a benchmark. Behaviour is FDN- and seed-dependent, so measure
8
+ your own case before assuming any of it transfers.
9
+
10
+
11
+ Flatness on the training grid depends on ``nfft``
12
+ =================================================
13
+
14
+ :class:`~pyFDN.FlatMagnitude` measures ``|H|`` at the model's DFT bins, so its
15
+ frequency resolution *is* the model's ``nfft``. The truncation to ``nfft``
16
+ samples is a rectangular window, so the peak-to-median range of ``|H|`` grows
17
+ with ``nfft``, and the mean-squared error weights the tallest modes ever more
18
+ heavily. Loss values are therefore comparable across runs at one ``nfft`` and
19
+ not across different ones. A multi-resolution loss
20
+ (:class:`~pyFDN.FlatSpectrogram`), whose analysis windows set their own
21
+ resolution, is the way out.
22
+
23
+ The optimization crosses long plateaus on ``FlatMagnitude``; ``train_fdn``'s
24
+ default ``patience=10`` stops inside one. Raise it for a converged fit.
25
+
26
+
27
+ Asymmetric flatness: peaks over dips
28
+ ====================================
29
+
30
+ :class:`~pyFDN.AsymmetricFlatMagnitude` raises the two sides of the deviation
31
+ from flat to different powers so peaks cost more than dips. The exponent, not a
32
+ weight, is what makes it bite: at ``peak_power=4`` a peak twice as tall costs
33
+ sixteen times as much. Flat stays the unique minimum at every ``peak_power``
34
+ (normalizing by RMS forces ``<(1 + d)^2> = 1``), and the loss is gain-invariant.
35
+
36
+ It is deliberately **not** in decibels: ``∂dB/∂|H| ∝ 1/|H|``, so in dB the
37
+ deepest nulls dominate the gradient however lightly weighted. In linear
38
+ magnitude the gradient is ``∝ p·(d⁺)^(p-1)``, largest at the tallest peaks,
39
+ while a dip is bounded at ``d = -1``.
40
+
41
+ The cost is steps and steadiness: that same gradient vanishes near the optimum,
42
+ so a higher exponent takes longer to converge and varies more from seed to seed.
43
+ The advantage over ``FlatMagnitude`` is not unconditional. Loss values are not
44
+ comparable across ``peak_power``, or with ``FlatMagnitude``; compare the
45
+ responses.
46
+
47
+
48
+ Multi-resolution flatness: average over frames first
49
+ ====================================================
50
+
51
+ :class:`~pyFDN.FlatSpectrogram` averages the short-time magnitudes over frames
52
+ into a Welch estimate *before* measuring flatness. Asking each individual frame
53
+ to be flat instead is actively harmful: an isolated echo inside a short frame
54
+ already has a flat frame spectrum, so that objective rewards an impulsive,
55
+ comb-filtered IR.
56
+
57
+
58
+ Energy decay vs. spectrogram distance
59
+ =====================================
60
+
61
+ :class:`~pyFDN.MatchEnergyDecay` compares octave-band Schroeder curves. A
62
+ magnitude spectrogram distance is not a substitute for fitting a decay: it
63
+ compares two signals frame by frame, and two rooms with identical decay have
64
+ uncorrelated fine structure, so predicting *silence* scores better there than
65
+ predicting the right amount of the wrong detail. Fitted to a measured room, a
66
+ spectrogram distance is minimized by an FDN whose RT falls well short of the
67
+ measurement, where an energy-decay loss is not.
68
+
69
+
70
+ Doubly-cumulated energy
71
+ =======================
72
+
73
+ :class:`~pyFDN.MatchCumulativeEnergy` integrates the short-time power spectrum
74
+ twice — backwards in time and along frequency — and scores the RMS difference of
75
+ the two surfaces after a compressive power.
76
+
77
+ **Why cumulate twice.** The time direction is Schroeder backward integration
78
+ (the reason ``MatchEnergyDecay`` exists). The frequency direction replaces
79
+ splitting into octave bands: band edges are an arbitrary quantization a fit can
80
+ satisfy on average while getting the shape wrong, whereas a cumulative sum is
81
+ the limit of ever-finer bands and is monotone and smooth in both axes, which a
82
+ gradient values. Read down the ``t = 0`` edge and you have the integrated
83
+ spectrum (colour); read across the ``f = 0`` edge and you have the full-band
84
+ decay; the interior ties them together band by band.
85
+
86
+ **Compression, not decibels.** The surface spans the whole dynamic range of the
87
+ decay, so a plain MSE would see only the first frames. Raising the normalized
88
+ surface to a fractional ``power`` (0.5 default) compresses that range while
89
+ staying bounded, its gradient ``∝ x^(p-1)`` finite everywhere the floor allows.
90
+ A logarithm is worse: it turns the silence *below* the response into an
91
+ unbounded penalty dominated by whichever bin is nearest zero.
92
+
93
+ **Which way the frequency cumulation runs.** Cumulating downwards alone — the
94
+ default, and the plain reading of "energy above this frequency" — leaves the
95
+ bottom octave with almost no gradient, and a fit that has to *find* a decay
96
+ tends to abandon it there. ``frequency="both"`` scores both directions and
97
+ averages, which recovers the low end; it is the setting to reach for when the
98
+ decay is not given. This is a matter of weighting rather than frequency
99
+ resolution, so a longer analysis window is not the fix.
@@ -7,12 +7,14 @@ All main functions are accessible directly from ``pyFDN``::
7
7
  import pyFDN
8
8
 
9
9
  feedback = pyFDN.random_orthogonal(4)
10
- absorption = pyFDN.first_order_absorption(1.2, 0.9, [100, 150, 200, 250], 48_000)
10
+ attenuation = pyFDN.decay_to_first_order_shelf(
11
+ 1.2, 0.9, None, [100, 150, 200, 250], 48_000
12
+ )
11
13
  gain_db = pyFDN.lin_to_db([0.5, 1.0, 2.0])
12
14
 
13
15
  Or import specific functions::
14
16
 
15
- from pyFDN import random_orthogonal, first_order_absorption, dss_to_ss
17
+ from pyFDN import random_orthogonal, decay_to_first_order_shelf, dss_to_ss
16
18
 
17
19
  feedback = random_orthogonal(4)
18
20
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyFDN"
7
- version = "0.3.0"
7
+ version = "0.4.1"
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.3.0"
116
+ current_version = "0.4.1"
117
117
  allow_dirty = false
118
118
  commit = true
119
119
  message = "Bump version: {current_version} → {new_version}"