Time-varying spectral filtering with frequency sweep, resonance control, and overlap-add processing for creative audio transformation and dynamic filtering effects.
This script implements an adaptive low-pass filter with time-varying cutoff frequency that sweeps between user-defined start and end frequencies over the duration of the audio. Using overlap-add spectral processing, it applies a smooth, continuously changing filter with adjustable resonance, transition width, and visual feedback. Unlike static filters, this adaptive approach creates dynamic filtering effects ideal for sound design, musical transitions, and creative audio processing where the spectral character evolves over time.
Key Features:
8 Curated Presets — From gentle sweeps to acid bass and underwater effects
Time-Varying Cutoff — Linear frequency sweep from start to end frequency
Adjustable Resonance — Peaking filter with controllable bandwidth (0=none to >1=self-oscillation)
Spectral Processing — Overlap-add method with cosine-tapered transition
Dual Visualization — Cutoff trajectory and filter response curves
True Stereo Support — Independent processing of left/right channels
Frame-Based Adaptation — Smooth parameter interpolation between analysis frames
Why Adaptive Filtering? Traditional filters apply fixed frequency characteristics, but many musical and sound design applications benefit from filters that evolve over time. This adaptive approach enables: (1) Dynamic effects: Create evolving textures and transitions. (2) Musical sweeps: Build tension/release with frequency movement. (3) Creative transformations: Morph between different spectral characters. (4) Time-based processing: Match filter changes to musical timing. The implementation uses: (1) Frame-based processing: Break audio into short frames (default 50ms). (2) Parameter interpolation: Smoothly vary cutoff frequency across frames. (3) Spectral multiplication: Apply frequency-domain filter to each frame. (4) Overlap-add synthesis: Recombine frames with Hanning windows for smooth transitions. (5) Resonance modeling: Gaussian peak addition for emphasis near cutoff. This creates professional-quality adaptive filtering entirely within Praat.
Technical Implementation: (1) Frame segmentation: Divide audio into overlapping frames with Hanning window. (2) Time-to-frequency: Convert each frame to spectrum via FFT. (3) Parameter calculation: Compute current cutoff frequency based on frame position. (4) Spectral filtering: Multiply spectrum by frequency response with cosine transition. (5) Resonance addition: Apply Gaussian peak if resonance > 0. (6) Frequency-to-time: Convert filtered spectrum back to time domain. (7) Overlap-add: Sum windowed frames with 50% overlap. (8) Visualization: Generate dual-panel plot showing cutoff trajectory and filter responses. The system handles mono/stereo automatically and includes comprehensive parameter validation.
Quick start
In Praat, select exactly one Sound object (mono or stereo).
Run script… → adaptive_low_pass_filter.praat.
Choose a Preset (start with "Gentle Sweep" for default behavior).
Set Start_cutoff_frequency: Starting cutoff in Hz (e.g., 200 Hz).
Set End_cutoff_frequency: Ending cutoff in Hz (e.g., 2000 Hz).
Set Resonance_bandwidth: Width of resonance peak in Hz (e.g., 100 Hz).
Adjust Filter_smoothing: Transition width in Hz (e.g., 100 Hz).
Set Frame_duration: Analysis frame length in seconds (0.05s typical).
Set Scale_peak: Output normalization (0.99 prevents clipping).
Enable Play_after_processing to hear result immediately.
Enable Draw_filter_response for visualization.
Click OK — spectral processing, filtering, and visualization will run.
Quick tip: Start with "Gentle Sweep" preset to understand basic behavior. For musical sweeps, try "Opening Filter" (low to high) or "Closing Filter" (high to low). For sound design, experiment with "Acid Bass" (high resonance) or "Underwater" (narrow bandwidth). The cutoff sweep creates the main effect: low→high = opening up, high→low = closing down. Resonance adds emphasis near cutoff: 0.2-0.5 for subtle peak, 0.8-1.2 for pronounced resonance. Filter_smoothing controls transition sharpness: lower = sharper cutoff, higher = gentler rolloff. Processing stages: (1) Frame segmentation with 50% overlap, (2) Spectral transformation, (3) Frequency-domain filtering, (4) Inverse transformation, (5) Overlap-add synthesis. The visualization shows exactly how cutoff changes over time and what the filter does at different points.
Important:NYQUIST LIMIT: Cutoff frequencies must be below Nyquist (sample_rate/2). PROCESSING TIME: Spectral processing is computationally intensive (10-60 seconds for long files). FRAME DURATION: Too short = poor frequency resolution, too long = poor time resolution. RESONANCE CAUTION: Values > 1.0 may cause instability or self-oscillation. STEREO PROCESSING: Left/right channels processed independently with identical parameters. OVERLAP-ADD ARTIFACTS: Very sharp filter changes may cause audible artifacts. VISUALIZATION: Draw_filter_response creates two-panel plot; disable for faster processing. PARAMETER RANGES: Filter_smoothing should be > 0, resonance_bandwidth > 0. TEMPORAL RESOLUTION: Filter changes smoothly across frames, not sample-by-sample. PEAK NORMALIZATION: Scale_peak < 1.0 prevents clipping but may reduce loudness.
Adaptive Filter Theory
Time-Varying Filter Fundamentals
🔄 Dynamic Frequency Response
Core concept: Filter parameters change continuously over time
Cutoff trajectory: Linear interpolation between start and end frequencies
Frame-based processing: Short-time analysis with parameter updates
Spectral multiplication: Frequency-domain filtering per frame
Overlap-add synthesis: Smooth reconstruction from filtered frames
Mathematical Framework
# ADAPTIVE FILTER MATHEMATICS
# 1. TIME-VARYING CUTOFF FREQUENCY
# Linear interpolation from start_fc to end_fc over duration T
fc(t) = start_fc + (end_fc - start_fc) × (t / T)
WHERE:
t = current time (0 to T)
T = total audio duration
start_fc = start_cutoff_frequency
end_fc = end_cutoff_frequency
# Example: start_fc = 200 Hz, end_fc = 2000 Hz, T = 10s
# At t = 0s: fc(0) = 200 Hz
# At t = 5s: fc(5) = 200 + (2000-200)×(5/10) = 1100 Hz
# At t = 10s: fc(10) = 2000 Hz
# 2. FRAME-BASED PARAMETER INTERPOLATION
# Audio divided into overlapping frames of duration frame_dur
# Frame index i = 1 to numFrames
# Frame start time: t_start[i] = (i-1) × hop_dur
# Frame mid time: t_mid[i] = t_start[i] + frame_dur/2
# Current cutoff for frame i: fc_i = fc(t_mid[i])
# Hop duration (50% overlap): hop_dur = frame_dur / 2
# Number of frames: numFrames = floor((T - frame_dur) / hop_dur) + 1
# 3. WINDOWING FOR OVERLAP-ADD
# Hanning window for analysis/resynthesis:
w[n] = 0.5 × (1 - cos(2π × n / (N-1))) for n = 0 to N-1
WHERE N = frame_samples = frame_dur × sample_rate
# 4. FREQUENCY RESPONSE FUNCTION
# Cosine-tapered low-pass filter with resonance
# Transition bounds:
low_bound = fc_i - (filter_smoothing / 2)
high_bound = fc_i + (filter_smoothing / 2)
# Basic low-pass response (no resonance):
H_basic(f) =
1 if f < low_bound
0.5 × (1 + cos(π × (f - low_bound) / (high_bound - low_bound)))
if low_bound ≤ f ≤ high_bound
0 if f > high_bound
# With resonance (Gaussian peak):
H_res(f) = H_basic(f) × (1 + resonance × exp(-((f - fc_i) / resonance_bandwidth)^2))
WHERE:
f = frequency in Hz
resonance = peak amplitude factor (0 = no resonance)
resonance_bandwidth = width of resonance peak
# 5. SPECTRAL MULTIPLICATION
# For each frame i:
# Input frame x_i[n] → FFT → Spectrum X_i[k]
# Apply frequency response: Y_i[k] = X_i[k] × H(f_k)
# Inverse FFT → filtered frame y_i[n]
# 6. OVERLAP-ADD SYNTHESIS
# Window filtered frames: y_i_w[n] = y_i[n] × w[n]
# Position in output: output[t_start[i]:t_start[i]+frame_dur] += y_i_w[n]
# 50% overlap ensures smooth reconstruction
# 7. CONTINUITY CONSIDERATIONS
# Filter changes smoothly between frames because:
# 1. fc_i changes gradually (linear interpolation)
# 2. 50% overlap provides temporal smoothing
# 3. Hanning window reduces frame boundary artifacts
# 4. Filter response changes continuously with fc_i
# RESULT: Smoothly time-varying filter with controlled evolution
Frame-Based Processing Architecture
🎯 Overlap-Add Method
Analysis: Hanning-windowed frames with 50% overlap
Parameter mapping: Time percentage maps to frequency percentage
Visualization: Cutoff trajectory shown as line plot
Sweep Implementation Details
# FREQUENCY SWEEP IMPLEMENTATION
# 1. SWEEP CALCULATION PER FRAME
FOR each frame i from 1 to numFrames:
# Frame timing
frame_start = (i - 1) × hop_duration
frame_mid = frame_start + frame_duration / 2
# Ensure within bounds
IF frame_mid > duration:
frame_mid = duration
# Progress percentage (0 to 1)
progress = frame_mid / duration
# Current cutoff frequency (linear interpolation)
current_cutoff = start_fc + (end_fc - start_fc) × progress
# 2. SWEEP DIRECTION CONSIDERATIONS
# Ascending sweep (start_fc < end_fc):
# - Creates "opening up" effect
# - Builds brightness over time
# - Example: 200 Hz → 2000 Hz
# Descending sweep (start_fc > end_fc):
# - Creates "closing down" effect
# - Reduces brightness over time
# - Example: 2000 Hz → 200 Hz
# 3. SWEEP RATE CALCULATION
sweep_rate_hz_per_sec = abs(end_fc - start_fc) / duration
# Example calculations:
# duration = 10s, start_fc = 200 Hz, end_fc = 2000 Hz
# sweep_rate = (2000-200)/10 = 180 Hz/s
# After 5s: cutoff = 200 + 180×5 = 1100 Hz
# 4. MUSICAL/PERCEPTUAL CONSIDERATIONS
# Logarithmic vs. linear perception:
# Human hearing is approximately logarithmic
# Linear Hz sweep may sound non-linear perceptually
# For more perceptually linear sweep, use logarithmic:
# current_cutoff = start_fc × (end_fc/start_fc)^progress
# 5. SWEEP APPLICATIONS:
# Opening Filter: Low → High (brightening)
# Closing Filter: High → Low (darkening)
# Narrow Band: Small range, focused movement
# Resonant Sweep: With emphasis peak following cutoff
# 6. PRESET SWEEP EXAMPLES:
# Gentle Sweep: 300 → 1500 Hz (moderate range)
# Sharp Transition: 100 → 3000 Hz (wide range)
# Narrow Band: 400 → 800 Hz (small range)
# Opening Filter: 150 → 8000 Hz (full spectrum open)
# Closing Filter: 8000 → 150 Hz (full spectrum close)
# Resonant Sweep: 200 → 4000 Hz (with resonance)
# Acid Bass: 150 → 3000 Hz (high resonance)
# Underwater: 800 → 300 Hz (descending, moderate resonance)
# 7. TEMPORAL ALIGNMENT
# The sweep is synchronized to audio duration
# Same sweep rate regardless of audio content
# For musically synchronized sweeps, match duration to musical phrases
# 8. BOUNDARY HANDLING
# Start and end frequencies clamped to Nyquist
# Smooth transition ensured by frame interpolation
# No abrupt changes at boundaries
Sweep Preset Configurations
Preset
Start (Hz)
End (Hz)
Direction
Range
Typical Use
Gentle Sweep
300
1500
Ascending
Moderate
General purpose, subtle evolution
Sharp Transition
100
3000
Ascending
Wide
Dramatic transformation
Narrow Band
400
800
Ascending
Narrow
Focused frequency movement
Opening Filter
150
8000
Ascending
Full
Full spectrum reveal
Closing Filter
8000
150
Descending
Full
Full spectrum closure
Resonant Sweep
200
4000
Ascending
Wide
Emphasized sweep with peak
Acid Bass
150
3000
Ascending
Moderate
High resonance for synth effects
Underwater
800
300
Descending
Moderate
Descending murky effect
Spectral Processing Method
Overlap-Add Spectral Processing
🔊 Frequency-Domain Filtering
Analysis: STFT with Hanning window, 50% overlap
Filtering: Complex spectral multiplication
Synthesis: Inverse STFT with overlap-add
Window choice: Hanning for good frequency resolution and sidelobe suppression
Overlap: 50% provides perfect reconstruction for smooth filters
Spectral Processing Algorithm
# SPECTRAL PROCESSING IMPLEMENTATION
# 1. FRAME EXTRACTION
FOR each frame i:
# Extract frame with Hanning window
frame_start = (i - 1) × hop_duration
frame_end = frame_start + frame_duration
# Handle end of file
IF frame_end > duration:
frame_end = duration
Extract part: frame_start, frame_end, "Hanning", 1, "no"
# Result: windowed frame ready for FFT
# 2. TIME → FREQUENCY TRANSFORM
To Spectrum: "yes" # Forward FFT with magnitude/phase
# Result: complex spectrum with N/2+1 frequency bins
# Frequency resolution: Δf = sample_rate / N
# Where N = frame_samples = frame_duration × sample_rate
# 3. FREQUENCY BIN TO HERTZ MAPPING
# Frequency of bin k: f_k = k × Δf
# For k = 0 to N/2 (DC to Nyquist)
# 4. SPECTRAL FILTER APPLICATION
# Create filter response array H[k] for each frequency bin
FOR each frequency bin k:
f_hz = k × Δf
# Calculate filter gain at this frequency
IF f_hz < low_bound:
gain = 1
ELSIF f_hz > high_bound:
gain = 0
ELSE:
# Cosine transition
gain = 0.5 × (1 + cos(pi × (f_hz - low_bound) / (high_bound - low_bound)))
# Apply resonance if enabled
IF resonance > 0:
resonance_factor = 1 + resonance × exp(-((f_hz - current_cutoff) / resonance_bandwidth)^2)
gain = gain × resonance_factor
# Apply to spectrum (complex multiplication)
# Real part: Re{Y[k]} = Re{X[k]} × gain
# Imag part: Im{Y[k]} = Im{X[k]} × gain
# In Praat: Spectrum Formula with conditional expressions
# 5. FREQUENCY → TIME TRANSFORM
To Sound # Inverse FFT
# Result: filtered time-domain frame
# Still windowed by analysis Hanning window
# 6. OVERLAP-ADD SYNTHESIS
# Position filtered frame in output buffer
output_start_sample = round(frame_start × sample_rate)
frame_length_samples = frame_duration × sample_rate
FOR sample j from 0 to frame_length_samples-1:
output_time = frame_start + j/sample_rate
output_index = output_start_sample + j
# Add windowed frame to output (overlap-add)
output[output_index] += filtered_frame[j] × window[j]
# 7. WINDOW CONSIDERATIONS
# Analysis window: Hanning w_analysis[n]
# No explicit synthesis window needed for 50% overlap
# Perfect reconstruction condition:
# Σ_i w_analysis[n - i×hop] = 1 for all n
# Satisfied by Hanning window with 50% overlap
# 8. COMPUTATIONAL EFFICIENCY
# FFT size: next power of 2 ≥ frame_samples
# Zero-padding may be used for efficient FFT sizes
# Praat handles FFT optimization automatically
# 9. ARTIFACT PREVENTION
# Smooth filter changes between frames
# Adequate frequency resolution (frame_duration ≥ 0.02s)
# 50% overlap for smooth reconstruction
# Avoid extreme resonance with sharp filters
# 10. PARAMETER TRADEOFFS
# frame_duration ↑ → frequency resolution ↑, time resolution ↓
# frame_duration ↓ → time resolution ↑, frequency resolution ↓
# Typical compromise: 0.02-0.05 seconds
Stereo processing: Identical parameters applied to both channels (true stereo)
Always use visualization to understand parameter effects before long processing
Troubleshooting Common Issues
Problem: Artifacts/clicks in output Cause: Frame duration too short, or filter changes too abrupt between frames Solution: Increase frame_duration to 0.05-0.10s, reduce sweep rate
Problem: Unwanted ringing or excessive resonance Cause: Resonance too high with narrow bandwidth Solution: Reduce resonance to 0.8 or below, increase resonance_bandwidth
Problem: Filter doesn't seem to change much Cause: Sweep range too small, or filter_smoothing too wide Solution: Increase frequency range (e.g., 200→4000 Hz), reduce filter_smoothing
Problem: Processing time extremely long Cause: Very long file with short frame duration Solution: Increase frame_duration, or process shorter segments
Problem: Output too quiet or distorts Cause: Resonance causing gain > 1.0, or scale_peak too low/high Solution: Reduce resonance, adjust scale_peak (0.95-0.99 typical)