Dynamic Tremolo Effect — User Guide

Frequency-dependent tremolo modulation: spectral-domain amplitude modulation with frequency-varying tremolo rates and high-frequency attenuation for complex, evolving tremolo textures.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 0.1 (2025) License: MIT License Repo: https://github.com/ShaiCohen-ops/Praat-plugin_AudioTools
Contents:

What this does

This script implements dynamic tremolo — a frequency-domain effect where tremolo rate and depth vary across the spectrum. Unlike traditional tremolo (uniform amplitude modulation), this processes audio in the spectral domain (FFT), applying different tremolo characteristics to different frequency regions. Low frequencies (below cutoff) receive cosine-squared modulation that varies by frequency. High frequencies (above cutoff) receive static attenuation. Result: complex, evolving tremolo textures where bass, mids, and treble pulsate at different rates, creating shimmering, chorusing, or phasing-like effects impossible with time-domain tremolo.

Key Features:

What is tremolo? Tremolo = periodic amplitude modulation (volume oscillation). Historical: (1) Acoustic tremolo: Natural voice/instrument vibrato (pitch + amplitude). (2) Electric tremolo: 1950s guitar amps (Fender, Vox), LFO modulates gain. (3) Studio tremolo: Tape speed variation, rotating speakers (Leslie). Traditional tremolo = single LFO affects entire signal uniformly. This script: spectral tremolo = each frequency gets independent modulation rate based on formula. Creates: shimmering textures, pseudo-chorusing, evolving phasing, frequency-dependent pulsation. Related to: spectral filtering, vocoding, frequency-domain effects processing.

Technical Implementation: (1) Convert to spectrum: FFT (Fast Fourier Transform) converts time-domain audio to frequency-domain representation, each "bin" = specific frequency with amplitude/phase. (2) Apply frequency-dependent modulation: For each frequency bin (col): If frequency < low_freq_cutoff (8000 Hz): modulation = tremolo_min + tremolo_max × cos²(frequency / divisor), cos² creates smooth oscillation 0→1→0, divisor controls oscillation rate (higher = slower), multiply bin amplitude by modulation factor, If frequency ≥ cutoff: multiply by high_freq_attenuation (static scaling 0.5-1.0). (3) Convert back to time domain: Inverse FFT reconstructs audio waveform, (4) Normalize: Scale peak to 0.9. Key insight: Cosine-squared modulation means adjacent frequencies modulate at different phases/rates → creates complex interference patterns in time domain. Not simple amplitude pulsation but frequency-dependent spectral animation.

Quick start

  1. In Praat, select exactly one Sound object.
  2. Run script…Dynamic_Tremolo_Effect.praat.
  3. Choose Preset: Default, Deep Tremolo, Subtle Tremolo, Fast Tremolo, or Strong High-Freq Attenuation.
  4. If Custom: adjust low_freq_cutoff (Hz), tremolo_minimum/maximum (depth), tremolo_frequency_divisor (rate), high_freq_attenuation.
  5. Click OK — processing applies spectral tremolo, auto-plays result.
Quick tip: Start with Default for balanced spectral tremolo. Try Deep Tremolo for dramatic pulsation. Use Subtle Tremolo for gentle shimmer without obvious modulation. Fast Tremolo creates rapid, chorusing-like effect. Strong High-Freq Attenuation emphasizes bass/mids, darkens treble. Processing time: 2-10 seconds depending on file length (FFT computation). Output named "originalname_tremolo". fast_fourier enabled by default for speed (may reduce quality slightly — disable for highest fidelity). keep_intermediate_objects: disable (default) to auto-clean spectrum object, enable for manual inspection.
Important: LONG RUNTIME WARNING — FFT processing computationally intensive, especially on long files (>1 minute). Processing time grows with duration. Very long files (>5 minutes) may take 30+ seconds. Consider trimming to representative section for experimentation. Very low tremolo_frequency_divisor (<100) creates extreme, potentially harsh modulation. Very low tremolo_minimum (<0.2) creates near-silence at modulation troughs. High cutoff (>12000 Hz) leaves little spectrum for attenuation. Low cutoff (<2000 Hz) attenuates most content. Extreme settings may produce artifacts: digital distortion, spectral smearing, aliasing-like sounds. Start conservative, increase parameters gradually.

Spectral Tremolo Theory

Time Domain vs Frequency Domain

Time-Domain Tremolo (Traditional)

Concept: Multiply entire waveform by LFO (Low-Frequency Oscillator)

output(t) = input(t) × [1 + depth × sin(2π × LFO_freq × t)] Characteristics: - All frequencies modulated identically - Single tremolo rate - Simple, uniform pulsation - Predictable, musical tremolo effect Example: 5 Hz tremolo at 50% depth → entire signal pulsates 5 times per second

Frequency-Domain Tremolo (This Script)

Concept: Apply different modulation to each frequency bin in spectrum

For each frequency bin f: if f < cutoff: modulation(f) = min + max × cos²(f / divisor) output(f) = input(f) × modulation(f) else: output(f) = input(f) × attenuation Characteristics: - Each frequency modulated differently - Tremolo rate varies across spectrum - Complex, evolving textures - Unpredictable interference patterns Example: divisor = 500 → 500 Hz has different modulation than 1000 Hz → creates phasing/chorusing artifacts

Fast Fourier Transform (FFT)

What is FFT?

Fourier Transform: Converts time-domain signal → frequency-domain representation

Time Domain (waveform): Amplitude vs Time Shows how signal changes over time Frequency Domain (spectrum): Amplitude vs Frequency Shows which frequencies are present FFT = Fast algorithm for Fourier Transform Efficient computation (O(N log N)) Standard for digital audio processing

Spectrum Representation

Frequency bins:

Example: 44100 Hz sample rate, 2048-point FFT Frequency resolution = 44100 / 2048 ≈ 21.5 Hz per bin Bin 0: 0 Hz (DC) Bin 1: 21.5 Hz Bin 100: 2150 Hz Bin 372: 8000 Hz (approx cutoff) Bin 1024: 22050 Hz (Nyquist)

Cosine-Squared Modulation

Formula

modulation = tremolo_min + tremolo_max × cos²(frequency / divisor)

Breakdown: 1. cos(frequency / divisor) - Oscillates between -1 and +1 - Divisor controls oscillation rate - Higher divisor = slower oscillation 2. cos²(...) - Square the result - Range becomes 0 to +1 (always positive) - Creates smooth, rounded modulation curve 3. tremolo_max × cos²(...) - Scale modulation depth - Range: 0 to tremolo_max 4. tremolo_min + ... - Offset modulation floor - Final range: tremolo_min to (tremolo_min + tremolo_max) Example: min=0.3, max=0.7, frequency=1000, divisor=500 cos(1000/500) = cos(2) ≈ -0.416 cos²(2) ≈ 0.173 0.7 × 0.173 ≈ 0.121 0.3 + 0.121 = 0.421 → Bin at 1000 Hz scaled to 42.1% of original

Why Cosine-Squared?

Advantages:

Visual comparison:

Linear modulation: Straight ramp up/down (harsh)
Sine modulation: Smooth but can go negative
Cosine-squared: Smooth, always positive, rounded peaks

Frequency-Dependent Rate

How Divisor Controls Rate

Formula: cos²(frequency / divisor)

Divisor = 500 (default): Frequency: 100 Hz → cos²(100/500) = cos²(0.2) Frequency: 1000 Hz → cos²(1000/500) = cos²(2.0) Frequency: 5000 Hz → cos²(5000/500) = cos²(10.0) Lower frequencies: argument smaller → slower phase change Higher frequencies: argument larger → faster phase change Result: High frequencies modulate faster than low frequencies

Perceptual Effect

Bass (100-500 Hz):

Mids (500-2000 Hz):

Treble (2000-8000 Hz):

🎼 Musical Metaphor

Imagine orchestra where each instrument (frequency) plays tremolo at different tempo:

  • Double bass: Slow tremolo (2 beats per bar)
  • Cello: Medium tremolo (4 beats per bar)
  • Violin: Fast tremolo (8 beats per bar)

Combined: polyrhythmic texture, not simple pulsation. This script creates similar effect in frequency domain.

High-Frequency Attenuation

Cutoff Mechanism

Two-region processing:

Region 1: Frequencies < cutoff (default 8000 Hz) → Apply dynamic tremolo modulation → Each frequency gets cos² modulation Region 2: Frequencies ≥ cutoff → Apply static attenuation → Multiply by high_freq_attenuation (0.5-1.0) → No tremolo, just volume reduction

Why Attenuate Highs?

Practical reasons:

Effect on timbre:

Attenuation = 1.0: No change (bypass high-freq processing)
Attenuation = 0.8: Gentle darkening, subtle roll-off
Attenuation = 0.6: Moderate darkening, clear treble reduction
Attenuation = 0.5: Strong darkening, muffled highs
Attenuation < 0.5: Extreme darkness, almost no treble

Complete Processing Pipeline

STEP 1: Time-Domain to Frequency-Domain input_sound → [FFT] → spectrum (waveform → frequency bins) STEP 2: Frequency-Dependent Modulation For each frequency bin f: if f < low_freq_cutoff: mod = tremolo_min + tremolo_max × cos²(f / divisor) spectrum[f] = spectrum[f] × mod else: spectrum[f] = spectrum[f] × high_freq_attenuation STEP 3: Frequency-Domain to Time-Domain spectrum → [IFFT] → output_sound (frequency bins → waveform) STEP 4: Normalization scale peak to 0.9 RESULT: Time-domain audio with complex spectral tremolo

Spectral Artifacts and Considerations

FFT Side Effects:
  • Spectral leakage: Frequency bins not perfectly isolated, some "bleeding"
  • Time smearing: Sharp transients slightly blurred by FFT windowing
  • Phase distortion: Modifying magnitude affects phase relationships
  • Edge artifacts: File boundaries may show slight discontinuities

Mitigation: Use fast_fourier for speed (accepts minor quality loss). Disable for critical applications. Normalize prevents clipping from modulation peaks. Avoid extreme parameters (very low min, very high max) to minimize artifacts.

Parameters & Presets

Preset Options

🎵 Default

Parameters: Cutoff 8000 Hz, Min 0.3, Max 0.7, Divisor 500, Atten 0.8

Character: Balanced spectral tremolo, moderate depth and rate

Best for: General use, exploring effect, textural enhancement

💫 Deep Tremolo

Parameters: Min 0.2, Max 0.9 (other defaults)

Character: Dramatic pulsation, wide modulation range 20-110%

Best for: Obvious tremolo effect, rhythmic emphasis, experimental

✨ Subtle Tremolo

Parameters: Min 0.4, Max 0.4 (range 40-80%)

Character: Gentle shimmer, barely noticeable modulation

Best for: Subtle animation, mixing enhancement, transparent processing

⚡ Fast Tremolo

Parameters: Divisor 200 (faster rate, other defaults)

Character: Rapid spectral modulation, chorusing-like, shimmering

Best for: Textural complexity, pseudo-chorus, animated pads

🌙 Strong High-Freq Attenuation

Parameters: Attenuation 0.5 (darker, other defaults)

Character: Darkened tremolo, muffled highs, warm low-mid focus

Best for: Lo-fi aesthetic, warm textures, reducing harshness

Custom Parameters

ParameterTypeDefaultDescription
presetoptionDefaultChoose preset (affects other params)
fast_fourierbooleanyesUse fast FFT (speed vs quality trade-off)
low_freq_cutoffpositive8000Frequency boundary (Hz) for tremolo region
tremolo_minimumpositive0.3Modulation floor (minimum amplitude scale)
tremolo_maximumpositive0.7Modulation range (added to minimum)
tremolo_frequency_divisorpositive500Controls modulation rate (higher = slower)
high_freq_attenuationpositive0.8Scaling for frequencies above cutoff
scale_peakpositive0.9Output normalization level
play_after_processingbooleanyesAuto-play result
keep_intermediate_objectsbooleannoRetain spectrum object for inspection

Parameter Details

low_freq_cutoff

Range: 1000-16000 Hz (practical 2000-12000 Hz)

Default: 8000 Hz

Effect:

tremolo_minimum

Range: 0.1-0.9 (practical 0.2-0.6)

Default: 0.3 (30%)

Effect: Sets modulation floor. Lower values = deeper troughs (more dramatic pulsation). Very low (<0.2) creates near-silence at modulation minimum.

tremolo_maximum

Range: 0.1-0.9 (practical 0.3-0.8)

Default: 0.7

Effect: Added to minimum to set modulation ceiling. Total range = min to (min+max). Example: min=0.3, max=0.7 → range 30-100%

tremolo_frequency_divisor

Range: 50-2000 (practical 100-1000)

Default: 500

Effect:

high_freq_attenuation

Range: 0.3-1.0

Default: 0.8 (20% reduction)

Effect:

Applications

Ambient / Atmospheric Music

Preset: Default or Subtle Tremolo

Use case: Animated pads, evolving textures

Effect: