Non-Linear Frequency Folding — User Guide

Spectral mirroring & folding: applies frequency‑domain reflections (folding) combined with sinusoidal modulation to create complex harmonic intermodulation, spectral knots, and alien‑like transformations through non‑linear frequency remapping.

Technique: Spectral Folding + Modulation Implementation: Praat Script Category: Experimental Spectral Processing Version: Advanced License: MIT License
Contents:

What this does

This script implements non‑linear frequency folding — a spectral processing technique that "folds" high frequencies back into lower ranges through mirror‑like reflections, creating complex intermodulation products and harmonic relationships. Unlike traditional pitch‑shifting or harmonizing, which preserve linear frequency relationships, folding creates non‑linear mappings where frequencies are reflected around multiple "mirror points" (folding_period intervals) and modulated by sinusoidal gain patterns. The result is a dense, often metallic or alien‑sounding transformation that preserves rhythmic and textural qualities while radically altering spectral content.

Key Features:

What is frequency folding? Frequency folding is a spectral operation where frequencies above a certain point are "folded" back into lower ranges, similar to aliasing but controlled and intentional:
  • Mirror reflection: Frequency f is reflected around multiples of folding_period
  • Mathematical form: f → |f - 2 × round(f/folding_period) × folding_period|
  • Effect: High frequencies become lower but with complex relationships to original
  • Modulation layer: Folded spectrum multiplied by (sin + cos)² gain pattern
  • Result: Creates "spectral knots" — dense clusters of harmonically related components
This technique is inspired by aliasing artifacts in digital systems, but here used creatively to generate novel timbres rather than avoid artifacts.

Technical Implementation: The script operates in the frequency domain: (1) Convert to Spectrum via FFT (fast_fourier option). (2) Apply folding formula to each frequency bin: frequencies below low_freq_threshold pass unchanged; higher frequencies are folded via reflection formula and multiplied by modulation pattern. (3) Convert back to Sound via inverse FFT. Optimization features include: optional downsampling to processing_sample_rate (default 22050 Hz) for speed, and chunked processing (divide long sounds into chunk_duration segments) for memory management. The formula is built once then applied to the entire spectrum (or each chunk).

Quick start

  1. In Praat, select exactly one Sound object to process.
  2. Run script…nonlinear_frequency_folding.praat.
  3. Choose a Preset (Default, Tight Knots, Loose Knots, etc.) or keep Default.
  4. Enable use_downsampling (recommended for speed) and set processing_sample_rate (22050 Hz default).
  5. Enable use_chunking for sounds >10 seconds (prevents memory issues).
  6. Adjust folding parameters if desired (folding_period, modulation divisors).
  7. Set scale_peak (0.88 default) and play_after_processing.
  8. Click OK — script converts, processes spectrum, converts back.
  9. Output appears as: originalName_spectral_knots.
  10. Watch Info window for progress (downsampling, chunking, processing steps).
Quick tip: Start with Default preset on a speech or music sound. Try Tight Knots for dense, metallic results; Loose Knots for more open, harmonically rich textures. For subtle effects, use High Preservation (preserves more low frequencies). Enable use_downsampling for faster processing (22050 Hz is fine for most spectral effects). For long sounds (>30 s), enable use_chunking with chunk_duration=10 s. Watch the Info window — it shows conversion to mono (if stereo), downsampling, chunk count, and processing steps. The effect is often extreme — start with short sounds to understand the transformation.
Important: SPECTRAL‑DOMAIN PROCESSING — involves FFT → manipulation → inverse FFT, which can cause pre‑echo/Time‑smearing artifacts, especially with transient sounds. MONO CONVERSION — stereo sounds are converted to mono (average of channels) before processing. DOWNSAMPLING EFFECTS — processing at lower sample rate reduces maximum frequency (Nyquist = sample_rate/2) and may alias frequencies above Nyquist. EXTREME TRANSFORMATION — folding creates radical spectral changes; original may become unrecognizable. MEMORY USAGE — FFT of long, high‑sample‑rate sounds requires significant memory; chunking mitigates this. PHASE ISSUES — folding and modulation affect phase relationships; may cause cancellation or comb‑filtering when mixed with original.

Frequency Folding Theory

The Mirror Folding Operation

🪞 Mathematical Folding Formula

Core reflection equation:

Given frequency f (Hz) and folding_period P: folded_f = |f - 2 × round(f/P) × P| Where: • round(x) = nearest integer to x • |x| = absolute value (always positive) • P = folding_period (e.g., 1000 Hz) Interpretation: • Frequencies are "reflected" around multiples of P • f at exactly n×P maps to 0 • f between n×P and (n+1)×P maps into range [0, P]

Example with P=1000 Hz:

f = 300 → round(300/1000)=0 → folded = |300 - 0| = 300 (unchanged) f = 1200 → round(1.2)=1 → folded = |1200 - 2×1×1000| = |1200-2000| = 800 f = 1800 → round(1.8)=2 → folded = |1800 - 2×2×1000| = |1800-4000| = 2200 f = 2200 → round(2.2)=2 → folded = |2200 - 2×2×1000| = |2200-4000| = 1800 f = 2500 → round(2.5)=3 → folded = |2500 - 2×3×1000| = |2500-6000| = 3500

Visualizing the Folding Pattern

📊 Frequency Mapping Diagram

Original Frequency (Hz)       Folded Frequency (Hz)
     0─P (0‑1000)        →        0‑1000      (unchanged)
     P─2P (1000‑2000)    →        1000‑0      (mirrored down)
    2P─3P (2000‑3000)    →        0‑1000      (folded up then down)
    3P─4P (3000‑4000)    →        1000‑0      (etc.)

Pattern repeats every 2P (2000 Hz):
  [0, P]       → [0, P]       (identity)
  [P, 2P]      → [P, 0]       (mirror)
  [2P, 3P]     → [0, P]       (fold)
  [3P, 4P]     → [P, 0]       (mirror)
  etc.

Effectively creates "spectral origami" — folding spectrum onto itself.
    

Why absolute value? Ensures folded frequency is always positive (negative frequencies would be complex conjugate in real signal, but we work with magnitude spectrum).

Sinusoidal Modulation Layer

📈 Amplitude Modulation Pattern

Modulation formula: (sin(f/sine_divisor) + cos(f/cosine_divisor))²

Component analysis:

sin(f/s₁) + cos(f/s₂) where s₁ = sine_modulation_divisor, s₂ = cosine_modulation_divisor Properties: • sin and cos are 90° out of phase → complex interference pattern • Squaring: (a+b)² = a² + b² + 2ab = sin²(f/s₁) + cos²(f/s₂) + 2·sin(f/s₁)·cos(f/s₂) • Using identity: 2·sin·cos = sin(2·angle) Result: Sum of three oscillatory components with different periods: 1. sin² component: period = π·s₁ 2. cos² component: period = π·s₂ 3. sin(2f(1/s₁ + 1/s₂)) component: sum frequency

Effect on spectrum: Creates amplitude "ripples" across frequency — alternating bands of boost and cut. The squared operation ensures all values are positive (no phase inversion).

Complete Signal Flow

🔄 Processing Pipeline

INPUT: Original sound (mono or stereo converted)

STEP 1: OPTIMIZATION PREPARATION
  • Convert to mono if stereo (average channels)
  • Downsample to processing_sample_rate if enabled
  • Split into chunks if chunking enabled

FOR EACH CHUNK (or whole sound):
  STEP 2: TIME → FREQUENCY DOMAIN
    • To Spectrum: fast_fourier (FFT with Hann window)
    • Result: complex spectrum (magnitude + phase)

  STEP 3: APPLY FOLDING FORMULA
    For each frequency bin f:
      if f < low_freq_threshold:
        output[f] = input[f]  (preserve lows)
      else:
        folded_f = |f - 2*round(f/folding_period)*folding_period|
        modulation = (sin(f/sine_divisor) + cos(f/cosine_divisor))^2
        output[f] = input[folded_f] × modulation

  STEP 4: FREQUENCY → TIME DOMAIN  
    • To Sound (inverse FFT)
    • Overlap‑add reconstruction

STEP 5: RECONSTRUCTION
  • Concatenate chunks if chunked
  • Resample back to original sample rate if downsampled
  • Scale peak to scale_peak
  • Rename to originalName_spectral_knots

OUTPUT: Processed sound
    

The Core Formula Explained

Complete Formula Construction

# Built in script: formula$ = "if col < " + string$(low_freq_threshold) + ... " then self[1, col] " + ... "else self[1, abs(col - 2 * round(col / " + string$(folding_period) + ") * " + string$(folding_period) + ")] " + ... "* (sin(col / " + string$(sine_modulation_divisor) + ") + cos(col / " + string$(cosine_modulation_divisor) + ")) ^ 2 fi" # Expanded with example values (low_freq_threshold=100, folding_period=1000, etc.): if f < 100 then output[f] = input[f] # Preserve lows else folded_index = abs(f - 2 * round(f/1000) * 1000) # Folding modulation = (sin(f/300) + cos(f/150)) ^ 2 # Modulation output[f] = input[folded_index] * modulation # Combine endif

Praat‑Specific Implementation Details

Spectrum object in Praat: • Frequency axis labeled in Hz (col = frequency in Hz) • self[1, col] = complex spectrum value at frequency col • Formula applied to each frequency bin independently • Praat handles magnitude/phase appropriately Why self[1, folded_index] not self[folded_index]: • Spectrum is a Matrix object in Praat • self[row, column] indexing • For spectrum: row=1 always, column=frequency in Hz • self[1, col] is correct syntax Frequency bin resolution: • FFT size determines frequency resolution • Bin spacing = sample_rate / FFT_size • folded_index may not align exactly with bin centers • Praat interpolates between bins when indexing fractional frequencies Complex value handling: • Multiplication by real modulation affects magnitude only • Phase preserved from input[folded_index] • Negative modulation would affect phase but (sin+cos)² ≥ 0

Mathematical Properties of the Formula

🔬 Analysis of Components

Folding function properties:

  • Periodicity: folded_f repeats every 2×folding_period
  • Symmetry: folded_f(f) = folded_f(2P - f) for f∈[P,2P]
  • Idempotent: Applying twice doesn't change result (folded of folded = folded)
  • Range: folded_f ∈ [0, folding_period]

Modulation function properties:

  • Range: (sin+cos)² ∈ [0, 4] (sin and cos each ∈ [-1,1])
  • Mean value: Average ≈ 1.0 (sin² avg=0.5, cos² avg=0.5, cross term avg=0)
  • Periodicity: Components periodic with periods 2π·sine_divisor and 2π·cosine_divisor
  • Always positive: No phase inversion from modulation

Combined effect: Creates frequency‑dependent amplitude modulation on already‑folded spectrum. The modulation's frequency (in Hz⁻¹ space) creates "beating" patterns in spectral domain.

Alternative Interpretation: Spectral Convolution View

🎛️ Time‑Domain Equivalent

Folding in frequency domain corresponds to convolution in time domain:

Let F(ω) = original spectrum Folding operation F(ω) → F(|ω - 2P·round(ω/P)|) is equivalent to: Time domain: f(t) * [Σ_n δ(t - n·T) * something_complex] where T = 1/P (time period) Modulation (sin+cos)² in frequency domain corresponds to: Time domain: f(t) * [convolution of three sinc‑like functions] Exact equivalence is complex due to absolute value and rounding. But conceptually: folding creates time‑domain echoes/interference.

Thus, the spectral processing creates effects similar to complex delay networks or comb filters, but with mathematical precision in frequency domain.

Preset Configurations

Preset 1: Default

⚙️ Balanced Settings

Parameters:

  • folding_period: 1000 Hz
  • sine_modulation_divisor: 300
  • cosine_modulation_divisor: 150
  • low_freq_threshold: 100 Hz

Folding behavior: Mirrors around 1000 Hz intervals. Frequencies 1000‑2000 Hz fold down to 1000‑0 Hz; 2000‑3000 Hz fold to 0‑1000 Hz, etc.

Modulation behavior: Sine period = 2π×300 ≈ 1885 Hz cycle, cosine period = 2π×150 ≈ 942 Hz cycle. Combined creates complex interference pattern.

Sonic character: Balanced between folding and modulation effects. Creates noticeable spectral transformation without extreme density.

Preset 2: Tight Knots

🎗️ Dense Spectral Clustering

Parameter change: folding_period = 500 Hz (half of default)

Effect: More frequent folding — spectrum folds every 500 Hz instead of 1000 Hz. Creates denser "knots" as more frequency ranges are compressed into 0‑500 Hz band.

Mathematical impact: With P=500, frequency range 0‑2000 Hz undergoes 4 fold segments (0‑500, 500‑1000, 1000‑1500, 1500‑2000) instead of 2 segments with P=1000.

Sonic character: Denser, more metallic, more extreme transformation. Higher frequencies get folded more times, creating complex intermodulation.

Best for: Extreme sound design, creating metallic textures, complete spectral reconstruction.

Preset 3: Loose Knots

🎗️ Open, Harmonically Rich

Parameter change: folding_period = 2000 Hz (double default)

Effect: Less frequent folding — spectrum folds every 2000 Hz. More frequencies pass through unchanged or undergo simpler transformations.

Mathematical impact: With P=2000, frequency range 0‑4000 Hz has only 2 fold segments (0‑2000, 2000‑4000). More spectral space between folds.

Sonic character: More open, less dense, retains more of original harmonic structure while still applying folding. Good for subtle‑to‑moderate effects.

Best for: Harmonic enhancement, adding complexity without overwhelming original, musical applications.

Preset 4: High Preservation

🎵 Protect Low Frequencies

Parameter change: low_freq_threshold = 500 Hz (5× default)

Effect: Frequencies below 500 Hz pass completely unchanged (no folding, no modulation). Only frequencies >500 Hz are processed.

Rationale: Bass frequencies often carry fundamental pitch and rhythm; preserving them maintains some connection to original while transforming higher harmonics.

Sonic character: Maintains bass/beat structure while transforming mid/high frequencies. More musically useful for rhythm‑based material.

Best for: Music processing where you want to keep bass/kick drum intact, vocal processing preserving low formants.

Preset 5: Fast Modulation

🌀 Rapid Amplitude Variations

Parameter changes:

  • sine_modulation_divisor = 150 (half default)
  • cosine_modulation_divisor = 75 (half default)

Effect: Modulation pattern cycles twice as fast across frequency axis. Creates more rapid alternation of boost/cut bands.

Mathematical impact: Modulation periods: sine = 2π×150 ≈ 942 Hz cycle, cosine = 2π×75 ≈ 471 Hz cycle. More cycles per octave.

Sonic character: Brighter, more detailed modulation effect. Folding combined with fast modulation creates intricate spectral patterns.

Best for: Adding fine‑grained texture, creating "shimmering" effects, detailed sound design.

Preset Comparison Table

Presetfolding_periodsine_divisorcosine_divisorlow_freq_thresholdCharacter
Default1000300150100Balanced
Tight Knots500300150100Dense, metallic
Loose Knots2000300150100Open, harmonic
High Preservation1000300150500Bass‑preserving
Fast Modulation100015075100Detailed, shimmering

Optimization Features

Downsampling for Speed

📉 Intelligent Sample Rate Reduction

When enabled (use_downsampling=1):

  • Original sound resampled to processing_sample_rate (default 22050 Hz)
  • All processing (FFT, folding, modulation) occurs at lower rate
  • Result resampled back to original sample rate

Why 22050 Hz?

  • Nyquist frequency = 11025 Hz — covers most audible content
  • FFT size halves compared to 44100 Hz → 4× speed improvement
  • Frequency resolution still adequate for folding effects
  • Human hearing sensitivity decreases above 10 kHz anyway

Mathematical impact:

FFT computation: O(N·logN) where N = FFT size N ≈ 2 × duration × sample_rate (for next power of 2) Example: 10 s sound: • At 44100 Hz: N ≈ 2×10×44100 = 882,000 → FFT size = 2²¹ = 2,097,152 • At 22050 Hz: N ≈ 2×10×22050 = 441,000 → FFT size = 2¹⁹ = 524,288 Speed improvement: (524288·log₂524288) / (2097152·log₂2097152) ≈ 0.25× time

When to disable: When processing high‑frequency content >11 kHz is critical, or for very short sounds where FFT overhead dominates.

Chunked Processing for Memory Management

🧩 Divide & Conquer Large Files

When enabled (use_chunking=1) and duration > chunk_duration:

  • Sound divided into chunks of chunk_duration seconds (default 10 s)
  • Each chunk processed independently (FFT → formula → inverse FFT)
  • Processed chunks concatenated back together

Benefits:

  • Memory: FFT requires memory ~2×N samples; chunking reduces peak memory
  • Stability: Prevents Praat crashes on very long files
  • Progress feedback: Shows chunk‑by‑chunk progress in Info window
  • Flexibility: Can adjust chunk_duration based on available memory

Chunk size recommendations:

Sound DurationRecommended chunk_durationWhy
<10 sDisable chunking (process whole)Overhead outweighs benefits
10‑60 s10 sBalanced memory/time
1‑5 min20 sFewer chunks, faster concatenation
>5 min30 sMinimize number of chunks

Formula Pre‑Building Optimization

⚡ Formula Construction Once

Key optimization in script:

# Formula built ONCE before processing: formula$ = "if col < " + string$(low_freq_threshold) + ... " then self[1, col] " + ... "else self[1, abs(col - 2 * round(col / " + string$(folding_period) + ") * " + string$(folding_period) + ")] " + ... "* (sin(col / " + string$(sine_modulation_divisor) + ") + cos(col / " + string$(cosine_modulation_divisor) + ")) ^ 2 fi"

Why this matters:

  • Performance: String concatenation done once, not per‑bin
  • Memory: Single formula string reused for all chunks
  • Accuracy: Ensures identical formula across entire processing
  • Debugging: Can print formula$ to verify correctness

Alternative (slower) approach: Re‑build formula for each frequency bin → O(N²) string operations.

Parameters Explained

Folding Parameters

ParameterTypeDefaultRangeDescription
folding_periodpositive100010‑10000Frequency interval for folding (Hz). Lower = denser knots.
low_freq_thresholdpositive1000‑5000Frequencies below this pass unchanged (Hz).
sine_modulation_divisorpositive30010‑1000Divisor for sin(f/divisor) in modulation.
cosine_modulation_divisorpositive15010‑1000Divisor for cos(f/divisor) in modulation.
fast_fourierbooleanyesyes/noUse FFT for spectral conversion (faster).

Optimization Parameters

ParameterTypeDefaultDescription
use_downsamplingboolean1Downsample to processing_sample_rate before processing.
processing_sample_ratepositive22050Target sample rate for processing (Hz).
use_chunkingboolean1Process in chunks for memory management.
chunk_durationpositive10Duration of each chunk (seconds).

Output Parameters

ParameterTypeDefaultDescription
scale_peakpositive0.88Peak amplitude scaling (0‑1). 0.88 prevents clipping.
play_after_processingboolean1Automatically play result after processing.

Parameter Interaction Tips

Important relationships:
  • folding_period vs low_freq_threshold: If low_freq_threshold > folding_period, folding won't affect frequencies below threshold (good for preserving bass).
  • sine_divisor vs cosine_divisor: Ratio affects modulation pattern. Equal divisors create simpler pattern; different divisors create complex interference.
  • processing_sample_rate vs folding_period: Ensure folding_period < processing_sample_rate/2 (Nyquist). With default 22050 Hz, keep folding_period < 11025 Hz.
  • chunk_duration vs memory: Larger chunks use more memory but fewer concatenation operations.

Sonic Applications

Creative Sound Design

🎨 Transform Ordinary Sounds

Vocal processing: Apply Tight Knots preset to spoken word — creates robotic, alien vocal effects with metallic resonances.

Percussion transformation: Process drum loops with High Preservation — maintains beat integrity while adding spectral complexity to hi‑hats and cymbals.

Ambient textures: Use Loose Knots on field recordings — creates evolving, harmonically rich pads from environmental sounds.

Synth processing: Apply Fast Modulation to simple synth tones — adds intricate spectral movement and "shimmer".

Musical Applications

🎵 Harmonic Reconstruction

Chord transformation: Process piano chords with Default preset — creates complex harmonic clusters with intermodulation products.

Melodic processing: Apply to monophonic instruments — generates artificial harmonics and sidebands that follow the melody.

Rhythmic effects: Use High Preservation on rhythmic material — maintains groove while adding spectral interest.

Texture building: Layer folded version with original — creates rich, evolving textures with beating patterns.

Experimental Techniques

🔬 Advanced Processing Chains

Iterative folding: Process sound, then process result again with different parameters — creates extremely dense, complex spectra.

Selective frequency ranges: Use Praat's filtering before folding — isolate specific frequency bands for targeted transformation.

Parallel processing: Process same sound with different presets, then mix — creates multi‑dimensional spectral effects.

Time‑varying parameters: Process in sections with different folding_period values — creates evolving spectral transformations.

Practical Workflow Examples

👽 Alien Voice Effect

Goal: Create robotic, alien vocal effect from speech

Settings:

  • Preset: Tight Knots
  • folding_period: 400 Hz (even denser than preset)
  • low_freq_threshold: 50 Hz (preserve vocal fundamentals)
  • use_downsampling: yes (22050 Hz)
  • scale_peak: 0.95 (louder output)

Result: Speech becomes metallic, robotic, with complex harmonic resonances.

🎶 Pad from Field Recording

Goal: Transform environmental sound into musical pad

Settings:

  • Preset: Loose Knots
  • folding_period: 1500 Hz (open, harmonic)
  • low_freq_threshold: 200 Hz (preserve some low texture)
  • use_chunking: yes (chunk_duration=20 s)
  • Add reverb after processing (external)

Result: Environmental sound becomes harmonically rich, evolving pad texture.

🥁 Complex Drum Processing

Goal: Add spectral complexity to drum loop while keeping beat

Settings:

  • Preset: High Preservation
  • low_freq_threshold: 300 Hz (preserve kick and snare fundamentals)
  • folding_period: 800 Hz
  • sine_divisor: 200, cosine_divisor: 100 (fast modulation)
  • Mix 50% folded with 50% original

Result: Drum loop maintains punch while gaining complex hi‑hat and cymbal textures.

Troubleshooting & Tips

Problem: Output sounds distorted/noisy
Causes: Too low folding_period, extreme modulation divisors, insufficient low_freq_threshold
Solutions: Increase folding_period, use more moderate modulation divisors, raise low_freq_threshold
Problem: Processing very slow
Causes: Long file without chunking, high sample rate without downsampling
Solutions: Enable use_chunking, enable use_downsampling with 22050 Hz
Problem: Output too quiet
Causes: Low scale_peak, folding concentrates energy in fewer frequencies
Solutions: Increase scale_peak to 0.95‑1.0, normalize after processing
Problem: Original unrecognizable after processing
Causes: Extreme folding (low folding_period), no low frequency preservation
Solutions: Use Loose Knots preset, increase low_freq_threshold, mix with original

Advanced Usage Notes

For best results:
  • Start subtle: Begin with Loose Knots or High Preservation before trying extreme settings
  • Use monitoring: Enable play_after_processing to immediately hear results
  • Experiment iteratively: Process, listen, adjust parameters, process again
  • Combine with effects: Add reverb, delay, or filtering after folding for enhanced results
  • Document settings: Note successful parameter combinations for reuse
  • Consider context: Folded sounds work well as background textures or special effects