%23%20gallery_category%3A%20Getting%20Started%0A%23%20gallery_description%3A%20Build%20a%20basic%20FLAMO%20FDN%2C%20inspect%20its%20response%2C%20and%20process%20a%20dry%20audio%20signal%20through%20it.%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.24.0%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Vanilla%20FDN%20(FLAMO)%0A%0A%20%20%20%20The%20shortest%20path%20from%20nothing%20to%20a%20reverberator%20you%20can%20listen%20to.%20%60pyFDN.fdn_build_gallery%60%20picks%20a%20complete%20set%20of%20FDN%20parameters%20%E2%80%94%20delays%2C%20an%20orthogonal%20feedback%20matrix%2C%20input%2Foutput%20gains%20and%20frequency-dependent%20absorption%20%E2%80%94%20and%20%60pyFDN.dss_to_flamo%60%20turns%20them%20into%20a%20FLAMO%20model%2C%20which%20is%20a%20differentiable%20torch%20module%20that%20also%20happens%20to%20render%20audio.%0A%0A%20%20%20%20Two%20things%20come%20out%20of%20that%20model%20here%3A%20its%20impulse%20response%2C%20which%20is%20the%20reverb%20on%20its%20own%2C%20and%20a%20dry%20recording%20pushed%20through%20it.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20torch%0A%0A%20%20%20%20import%20pyFDN%0A%0A%20%20%20%20return%20np%2C%20pyFDN%2C%20torch%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Build%20the%20model%0A%0A%20%20%20%20Eight%20delay%20lines%20at%2048%20kHz%2C%20decaying%20over%202%20s%20at%20DC%20and%20half%20that%20at%20Nyquist%20%E2%80%94%20the%20frequency-dependent%20absorption%20every%20real%20room%20has.%20%60dss_to_flamo%60%20takes%20the%20build's%20matrices%2C%20delays%20and%20per-line%20filters%20and%20returns%20the%20FLAMO%20model%3B%20%60flamo_time_response%60%20renders%20its%20impulse%20response.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(pyFDN%2C%20torch)%3A%0A%20%20%20%20torch.manual_seed(42)%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20fs%20%3D%2048000%0A%0A%20%20%20%20build%20%3D%20pyFDN.fdn_build_gallery(%0A%20%20%20%20%20%20%20%20n%2C%0A%20%20%20%20%20%20%20%20fs%3Dfs%2C%0A%20%20%20%20%20%20%20%20io_type%3D%22ones%22%2C%0A%20%20%20%20%20%20%20%20direct_gain%3D1.0%2C%0A%20%20%20%20%20%20%20%20rt%3D2.0%2C%0A%20%20%20%20%20%20%20%20rt_nyquist%3D0.5%2C%0A%20%20%20%20%20%20%20%20output_gain_db%3D0.0%2C%0A%20%20%20%20%20%20%20%20output_gain_db_nyquist%3D-6.0%2C%0A%20%20%20%20%20%20%20%20rng%3D42%2C%0A%20%20%20%20)%0A%20%20%20%20model%20%3D%20pyFDN.dss_to_flamo(%0A%20%20%20%20%20%20%20%20build.A%2C%0A%20%20%20%20%20%20%20%20build.B%2C%0A%20%20%20%20%20%20%20%20build.C%2C%0A%20%20%20%20%20%20%20%20build.D%2C%0A%20%20%20%20%20%20%20%20build.delays%2C%0A%20%20%20%20%20%20%20%20build.fs%2C%0A%20%20%20%20%20%20%20%20nfft%3D2**18%2C%0A%20%20%20%20%20%20%20%20post_delay%3Dbuild.post_delay%2C%0A%20%20%20%20%20%20%20%20post_output%3Dbuild.post_output%2C%0A%20%20%20%20)%0A%20%20%20%20ir%20%3D%20pyFDN.flamo_time_response(model).flatten()%0A%20%20%20%20return%20build%2C%20fs%2C%20ir%2C%20model%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20What%20the%20model%20is%20made%20of%0A%0A%20%20%20%20Feedback%20matrix%2C%20delays%2C%20input%20and%20output%20gains%2C%20and%20the%20magnitude%20response%20the%20absorption%20filters%20impose%20on%20each%20delay%20line.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(build%2C%20pyFDN)%3A%0A%20%20%20%20pyFDN.plot_FDN_build(build%2C%20title%3D%22Vanilla%20FDN%20parameters%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20The%20impulse%20response%0A%0A%20%20%20%20A%20dense%20exponential%20decay%20whose%20high%20end%20dies%20first%2C%20which%20is%20the%20audible%20signature%20of%20the%20Nyquist%20reverberation%20time%20being%20shorter%20than%20the%20one%20at%20DC.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fs%2C%20ir%2C%20mo%2C%20np%2C%20pyFDN)%3A%0A%20%20%20%20_fig%20%3D%20pyFDN.plot_impulse_response(%0A%20%20%20%20%20%20%20%20ir%2C%0A%20%20%20%20%20%20%20%20fs%3Dfs%2C%0A%20%20%20%20%20%20%20%20title%3D%22Vanilla%20FDN%20impulse%20response%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20mo.vstack(%5B_fig%2C%20mo.audio(np.asanyarray(ir)%2C%20fs)%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Run%20audio%20through%20it%0A%0A%20%20%20%20The%20same%20model%2C%20driven%20by%20a%20signal%20instead%20of%20an%20impulse.%20%60flamo_process%60%20renders%20the%20model's%20frequency%20response%20once%20and%20convolves%3B%20%60tail_seconds%60%20appends%20enough%20silence%20for%20the%20tail%20to%20finish%20rather%20than%20wrapping%20back%20onto%20the%20start.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fs%2C%20mo%2C%20model%2C%20np%2C%20pyFDN)%3A%0A%20%20%20%20dry%2C%20_%20%3D%20pyFDN.load_audio(%22synth_dry%22%2C%20fs%3Dfs)%0A%20%20%20%20%23%20Reserve%202%20s%20of%20trailing%20silence%20so%20the%20reverb%20tail%20does%20not%20wrap%20around.%0A%20%20%20%20wet%20%3D%20pyFDN.flamo_process(model%2C%20dry%2C%20fs%3Dfs%2C%20tail_seconds%3D2.0)%0A%0A%20%20%20%20mo.hstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22Dry%3A%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.audio(np.asanyarray(dry)%2C%20fs)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22Wet%3A%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.audio(np.asarray(wet)%2C%20fs)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
9b6253d54910b7ed23ae204433a0246e