From 08ee1ff32b4d425134bc8d37c7cd2a31ff6ca94e Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Fri, 19 Feb 2021 17:34:41 -0500 Subject: Add FFT-based reverb --- fft.bqn | 20 ++++++++++++++++++++ mix.bqn | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 fft.bqn diff --git a/fft.bqn b/fft.bqn new file mode 100644 index 0000000..2d10ccf --- /dev/null +++ b/fft.bqn @@ -0,0 +1,20 @@ +# Fast Fourier transform +# Argument has shape ⟨l⟩ for real values or ⟨2,l⟩ for complex, l←2⋆n +# Result is complex encoded as shape ⟨2,l⟩. + +Sin‿Cos ← •math + +{ + 𝕨𝕊⁼𝕩: (-𝕨1⊘≢¯1)𝕊𝕩 ; + + inv ← 𝕨≡¯1 + "FFT argument must be a list or have two list cells" ! (3⌊=)◶⟨0,1,2=≠,0⟩𝕩 + n ← 2 ⋆⁼ l ← ¯1⊑≢𝕩 + "FFT length must be a power of two" ! ⌊⊸=n + s ← 2 ⥊˜ n + + r ← (Cos≍Sin) π × (1↓s) ⥊ -⍟inv ↕⊸÷ l÷2 # Roots of unity + M ← -˝∘× ≍ +˝∘×⟜⌽ # Complex multiplication + F ← { 𝕨 ⊏⎉1⊸𝕊⍟(1<=𝕨) (+˝˘≍⎉(-=𝕨)𝕨M-˝˘)𝕩 } # FFT loop + ÷⟜l⍟inv ⥊˘ r F s⊸⥊˘ ≍⟜(0¨)⍟(1==) 𝕩 +} diff --git a/mix.bqn b/mix.bqn index 21172c0..e8ad794 100644 --- a/mix.bqn +++ b/mix.bqn @@ -1,5 +1,6 @@ "mix.bqn takes a single option namespace, or no arguments" ! 1≥≠•args o ← ≠◶⟨•Import∘"options.bqn", ⊑⟩ •args +fft ← •Import "fft.bqn" # List of length |𝕩 that starts at 0 and stops just before 1, # reversed if 𝕩<0. @@ -40,3 +41,22 @@ _crossfade ⇐ { G←↑≍○<↓ (-𝕗)⊸G⊸(∾ 1⌽∾˜○(1⊸↓) ∾⟜< (¬⊸≍I𝕗)+˝∘×≍○⊑)⟜(𝕗⊸G)⎉1 } + +# Apply reverb impulse response (IR) 𝕨 to 𝕩. +# Argument rows are extended, giving result length (𝕩+○≠𝕨)-1 (for lists). +# Equivalent to (+´¨+⌜○↕○≠⊔×⌜)⎉1 except for numeric precision. +Reverb ⇐ { + M ← -˝∘× ≍ +˝∘×⟜⌽ # Complex multiplication + lw‿lx ← (¯1⊑≢)¨ 𝕨‿𝕩 + ! 0