Neural Granular Texture Morpher — User Guide

AI-driven granular synthesis with unsupervised learning: analyzes audio textures, clusters similar sonic characteristics using K-Means, and generates evolving morphing textures that intelligently transition between discovered sonic categories.

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 a neural granular texture morpher that combines granular synthesis with unsupervised machine learning to analyze, categorize, and regenerate audio textures. Unlike traditional granular synthesis that uses random or sequential grain selection, this system employs K-Means clustering to discover natural sonic categories within your audio and creates intelligent morphing patterns that transition between these discovered textures.

Key Features:

What is neural granular synthesis? Traditional granular synthesis: breaks audio into small grains and reassembles them. Neural granular synthesis: uses machine learning to understand and organize the sonic characteristics of grains before reassembly. The system works in three phases: (1) Feature extraction: Analyze each grain across multiple acoustic dimensions, (2) Clustering: Group similar grains into texture categories using K-Means, (3) Intelligent synthesis: Generate new textures by morphing between clusters. Advantages: (1) Context-aware: Understands relationships between different sonic elements, (2) Natural transitions: Creates musically coherent texture morphing, (3) Discovery: Reveals hidden structure in complex sounds, (4) Creative control: Parameters influence the "intelligence" of texture organization.

Technical Implementation: (1) Granular Analysis: Divide audio into overlapping grains, extract 5 acoustic features per grain. (2) Feature Normalization: Apply Z-score standardization for balanced clustering. (3) K-Means Clustering: Implement manual Expectation-Maximization algorithm to group grains into texture clusters. (4) Morphing Synthesis: Generate output by cycling through clusters at controlled speed, randomly selecting grains from target clusters. (5) Robust Concatenation: Use table-based object management for memory-safe grain assembly. Key insight: The "neural" aspect comes from the unsupervised learning that discovers natural categories in your audio, enabling intelligent rather than random grain selection.

Quick start

  1. In Praat, select exactly one Sound object with interesting textures.
  2. Run script…neural_granular_morpher.praat.
  3. Analysis Parameters:
    • grain_size_ms – Duration of each analysis grain (default: 60ms)
    • overlap_ratio – Overlap between consecutive grains (default: 0.5)
    • max_frequency_hz – Maximum frequency for analysis (default: 8000Hz)
    • number_of_clusters – Texture categories to discover (default: 4)
  4. Synthesis Parameters:
    • output_duration_sec – Length of generated texture (default: 10.0s)
    • morph_speed_hz – Speed of texture transitions (default: 0.5Hz)
  5. Enable play_result for immediate preview.
  6. Click OK – processing begins with progress updates in Info window.
  7. The script executes four phases:
    • Feature Extraction – Analyzing grains and extracting acoustic features
    • Neural Clustering – Learning texture categories (K-Means training)
    • Generative Synthesis – Creating morphing texture output
    • Final Assembly – Combining grains into final result
  8. Result appears as "originalname_TextureMorph" with peak normalization applied.
Quick tip: Start with texture-rich source material – environmental recordings, complex instrumental tones, or vocal phrases with varied articulation. Use 4-6 clusters for most material – too few may oversimplify, too many may create chaotic transitions. 60-100ms grain sizes work well for most textures. Slow morph speeds (0.2-0.5Hz) create gradual, evolving changes while faster speeds (1-2Hz) create rhythmic texture patterns. The algorithm works best with mono sources – stereo files are automatically converted to mono for analysis.
Important: PROCESSING INTENSIVE – this script performs complex analysis and may take several minutes for long files. Source requirements: Audio should be at least 2× grain duration and contain varied textures for meaningful clustering. Memory management: Very long outputs may require significant memory – use shorter output durations if experiencing issues. Cluster validation: The script checks for empty clusters and may exit if insufficient distinct textures are found. Progress monitoring: Watch the Info window for phase completion messages and error reports.

Analysis Phase

Granular Decomposition

🔬 Multi-Feature Acoustic Analysis

Grain extraction: Overlapping window analysis across entire sound

Feature set: 5 complementary acoustic descriptors

Normalization: Z-score standardization for balanced clustering

Output: Feature matrix for machine learning

Grain Calculation

Granular analysis parameters:

Grain timing calculations: grain_seconds = grain_size_ms / 1000 step_seconds = grain_seconds × (1 - overlap_ratio) number_of_grains = floor((duration - grain_seconds) / step_seconds) Example (default settings): grain_size_ms = 60 → grain_seconds = 0.06 overlap_ratio = 0.5 → step_seconds = 0.03 10-second audio → n_grains = floor((10 - 0.06) / 0.03) ≈ 331 grains Grain extraction: FOR each grain i from 1 to n_grains: center_time = (i - 0.5) × step_seconds start_time = center_time - (grain_seconds / 2) end_time = center_time + (grain_seconds / 2) Extract window with Hanning window function

Acoustic Feature Extraction

Five-Dimensional Feature Space

Feature Description Acoustic Property Analysis Method
Spectral Centroid Center of spectral mass Brightness vs darkness Spectrum centre of gravity
Spectral Bandwidth Spread of spectral energy Tone vs noise character Spectrum standard deviation
Fundamental Frequency Pitch (F0) in Hertz Perceived pitch Pitch analysis with cubic interpolation
Harmonicity Harmonic-to-noise ratio Tonality vs noisiness Harmonicity (CC) method
Intensity Acoustic intensity in dB Loudness/amplitude Intensity with 75Hz minimum

Feature Extraction Implementation

// Create analysis objects To Spectrogram: grain_seconds, max_frequency_hz, step_seconds, 20, "Gaussian" To Pitch: step_seconds, 75, 600 To Harmonicity (cc): step_seconds, 75, 0.1, 1.0 To Intensity: 75, step_seconds, "yes" // Extract features for each grain FOR each grain i from 1 to n_grains: t = (i - 0.5) × step_seconds // Spectral features from spectrogram slice To Spectrum (slice): t centroid = Get centre of gravity: 2 bandwidth = Get standard deviation: 2 // Pitch with undefined handling f0 = Get value at time: t, "Hertz", "Linear" IF f0 = undefined: f0 = 0 // Harmonicity with undefined handling hnr = Get value at time: t, "cubic" IF hnr = undefined: hnr = -50 // Intensity with undefined handling intensity = Get value at time: t, "cubic" IF intensity = undefined: intensity = -100 // Store in feature table Set value: i, 1, centroid Set value: i, 2, bandwidth Set value: i, 3, f0 Set value: i, 4, hnr Set value: i, 5, intensity

Feature Normalization

Z-Score Standardization

Manual normalization implementation:

FOR each feature column j from 1 to 5: // Calculate mean sum_j = 0 FOR i from 1 to n_grains: sum_j = sum_j + value[i,j] mean_j = sum_j / n_grains // Calculate standard deviation sum_sq_j = 0 FOR i from 1 to n_grains: diff = value[i,j] - mean_j sum_sq_j = sum_sq_j + diff × diff sd_j = sqrt(sum_sq_j / n_grains) IF sd_j = 0: sd_j = 1 (prevent division by zero) // Apply normalization FOR i from 1 to n_grains: z_score = (value[i,j] - mean_j) / sd_j Set value: i, j, z_score This ensures: Each feature has mean = 0, standard deviation = 1 All features contribute equally to distance calculations Prevents features with large numeric ranges from dominating

Neural Clustering Phase

K-Means Algorithm

🧠 Unsupervised Texture Discovery

Algorithm: Manual K-Means clustering with Expectation-Maximization

Process: Iteratively assign grains to clusters and update cluster centers

Convergence: Stops when assignments stabilize or max iterations reached

Output: Organized grain clusters representing distinct textures

K-Means Mathematics

Manual implementation details:

Initialization: Randomly select k grains as initial centroids Create centroid table: k rows × 5 features Expectation-Maximization Loop (max 10 iterations): E-Step (Assignment): FOR each grain i from 1 to n_grains: min_distance = very large number FOR each cluster c from 1 to k: distance² = Σ[f=1 to 5] (grain_feature[f] - centroid[c,f])² IF distance² < min_distance: min_distance = distance² best_cluster = c Assign grain i to best_cluster M-Step (Update): FOR each cluster c from 1 to k: count = number of grains assigned to cluster c IF count > 0: FOR each feature f from 1 to 5: sum_f = Σ[grains in cluster c] grain_feature[f] new_centroid = sum_f / count Update centroid[c,f] = new_centroid Convergence check: IF no grains changed clusters → exit loop

Cluster Organization

Texture Category Discovery

Post-clustering organization:

// Count grains in each cluster FOR c from 1 to k: cluster_count_'c' = 0 // Build cluster membership lists FOR i from 1 to n_grains: c = assigned_cluster[i] idx = cluster_count_'c' + 1 cluster_count_'c' = idx cluster_'c'_grain_'idx' = i // Validate clusters valid_clusters = 0 FOR c from 1 to k: IF cluster_count_'c' > 0: valid_clusters = valid_clusters + 1 // Error handling IF valid_clusters < 2: Exit: "Not enough distinct textures found"

Cluster Interpretation

Understanding Discovered Textures

Common Cluster Types Discovered:

Cluster 1: Bright Tonal
- High spectral centroid (bright)
- Clear fundamental frequency (tonal)
- High harmonicity (clean tones)
- Examples: Bell-like sounds, vocal vowels

Cluster 2: Dark Noisy
- Low spectral centroid (dark)
- Weak or noisy pitch
- Low harmonicity (noisy)
- Examples: Breath sounds, noise bursts

Cluster 3: Mid-Range Complex
- Medium spectral centroid
- Complex spectral structure
- Mixed harmonic/noise content
- Examples: Consonants, textured instruments

Cluster 4: Loud Transients
- High intensity values
- Brief temporal features
- Various spectral characters
- Examples: Drum hits, percussive sounds

Synthesis Phase

Morphing Algorithm

🔄 Intelligent Texture Transition

Morph logic: Cyclic progression through cluster space

Grain selection: Random sampling from target clusters

Timing control: Precise morph speed in Hz

Memory management: Block-based processing for stability

Morphing Mathematics

Cluster progression algorithm:

Morph cycle calculation: total_grains_needed = ceil(output_duration / step_seconds) FOR each output grain g from 1 to total_grains_needed: output_time = g × step_seconds cycle_position = (output_time × morph_speed_hz) × k target_cluster_float = (cycle_position mod k) + 1 target_cluster = round(target_cluster_float) // Boundary checking IF target_cluster < 1: target_cluster = 1 IF target_cluster > k: target_cluster = k IF cluster_count_'target_cluster' = 0: target_cluster = 1 Grain selection: random_index = randomInteger(1, cluster_count_'target_cluster') source_grain = cluster_'target_cluster'_grain_'random_index' source_time = (source_grain - 0.5) × step_seconds This creates: Continuous cycling through cluster space Controlled by morph_speed_hz parameter Random variation within each cluster

Block-Based Assembly

Memory-Safe Grain Concatenation

Robust implementation strategy:

// Process in blocks of 50 grains block_size = 50 Create TableOfReal: "BlockIDs", 10000, 1 block_count = 0 WHILE grains_generated < total_grains_needed: // Generate block Create TableOfReal: "GrainIDs", block_size, 1 grains_in_block = 0 FOR b from 1 to block_size: // Morph logic to select source grain source_grain = calculate_using_morph_algorithm() extract_grain(source_grain) grains_in_block = grains_in_block + 1 Store grain ID in grain table // Safe concatenation IF grains_in_block > 0: Read all grain IDs into variables Select all grain objects using variable names IF grains_in_block > 1: Concatenate → block_sound ELSE: Copy single grain → block_sound Store block ID in block table Remove individual grain objects Remove grain table // Final assembly IF block_count > 0: Read all block IDs into variables Select all block objects IF block_count > 1: Concatenate → final_output ELSE: Copy single block → final_output Remove block objects

Morph Speed Effects

Controlling Texture Transition Rate

Morph Speed Cycle Time (4 clusters) Musical Character Best For
0.1 Hz 10 seconds Very slow, evolving Ambient, background textures
0.25 Hz 4 seconds Slow, noticeable changes Evolving pads, soundscapes
0.5 Hz 2 seconds Moderate, musical General texture morphing
1.0 Hz 1 second Fast, rhythmic Rhythmic patterns, pulses
2.0 Hz 0.5 seconds Very fast, intense Glitch effects, rapid changes

Parameters

Analysis Parameters

Parameter Type Range Default Description
grain_size_ms positive 20-200 ms 60 ms Duration of each analysis grain
overlap_ratio positive 0.1-0.9 0.5 Overlap between consecutive grains
max_frequency_hz positive 4000-16000 Hz 8000 Hz Maximum frequency for spectral analysis
number_of_clusters integer 2-8 4 Number of texture categories to discover

Synthesis Parameters

Parameter Type Range Default Description
output_duration_sec positive 1.0-60.0 s 10.0 s Duration of generated texture output
morph_speed_hz positive 0.1-5.0 Hz 0.5 Hz Speed of texture transitions
play_result boolean 0/1 1 Auto-play after processing

Parameter Effects Guide

grain_size_ms Effects:
20-40 ms: Very short, granular texture
40-80 ms: Standard granular character
80-120 ms: Smoother, more tonal results
120-200 ms: Almost micro-sampling character

overlap_ratio Effects:
0.1-0.3: Sparse, separated grains
0.3-0.5: Moderate overlap, some grain identity
0.5-0.7: Smooth transitions, less graininess
0.7-0.9: Very smooth, almost continuous

number_of_clusters Effects:
2 clusters: Simple binary texture alternation
3-4 clusters: Clear texture categories
5-6 clusters: Complex, detailed texture mapping
7-8 clusters: Very detailed, potentially chaotic

morph_speed_hz Effects:
0.1-0.3 Hz: Very slow, evolving changes
0.3-0.7 Hz: Musical, noticeable transitions
0.7-1.5 Hz: Fast, rhythmic texture changes
1.5-5.0 Hz: Very fast, intense morphing

Applications

Sound Design & Textures

Use case: Creating evolving soundscapes and complex textures from simple sources

Technique: Use environmental recordings with moderate cluster counts

Examples: Evolving pads, atmospheric beds, synthetic environments

Vocal Processing

Use case: Transforming vocal recordings into textured vocal beds

Technique: Process vocal phrases with 4-6 clusters for articulation variety

Results: Evolving vocal textures, ghost choir effects, articulated pads

Instrumental Transformation

Use case: Creating new instrumental textures from acoustic recordings

Technique: Use instrumental phrases with varied playing techniques

Applications: Textural orchestration, synthetic instrument creation

Rhythmic Textures

Use case: Generating complex rhythmic patterns from percussive material

Technique: Fast morph speeds with percussive source material

Results: Evolving rhythmic patterns, complex groove textures

Practical Workflow Examples

🌊 Ocean Texture Evolution

Goal: Create evolving ocean-like textures from water recordings

Settings:

  • grain_size_ms: 80 (smooth water character)
  • overlap_ratio: 0.6 (smooth transitions)
  • clusters: 4 (wave types, splashes, etc.)
  • morph_speed: 0.3 Hz (slow, natural evolution)
  • output_duration: 30.0 s (long texture bed)

Result: Continuously evolving ocean texture that cycles through different water sound characteristics naturally.

🎤 Vocal Texture Bed

Goal: Transform spoken word into evolving vocal texture

Settings:

  • grain_size_ms: 50 (capture phoneme transitions)
  • overlap_ratio: 0.5 (balanced grain identity)
  • clusters: 5 (vowels, consonants, breaths, etc.)
  • morph_speed: 0.4 Hz (musical transition rate)
  • output_duration: 15.0 s (usable texture length)

Result: Evolving vocal texture that intelligently cycles through different speech articulations and qualities.

🥁 Rhythmic Texture Generator

Goal: Create complex rhythmic patterns from drum loops

Settings:

  • grain_size_ms: 40 (percussive character)
  • overlap_ratio: 0.4 (clear grain separation)
  • clusters: 3 (kicks, snares, cymbals)
  • morph_speed: 1.2 Hz (rhythmic pattern rate)
  • output_duration: 8.0 s (loop-friendly length)

Result: Rhythmic texture that cycles through different drum sound categories creating complex, evolving patterns.

Advanced Techniques

Creative parameter combinations:
  • Extreme clustering: Use 7-8 clusters with very textured sources for maximum complexity
  • Micro-granular: 20-30ms grains with high overlap for granular cloud effects
  • Macro-textures: 150-200ms grains with low overlap for almost sampling-like results
  • Rhythmic morphing: Match morph speed to musical tempo for rhythmic synchronization

Experiment with source material that has clear categorical differences for the most interesting results

Source material optimization:
  • Best sources: Environmental recordings, vocal phrases, instrumental performances with varied articulation
  • Good sources: Complex synthetic sounds, textured noise sources, field recordings
  • Challenging sources: Very uniform material, single sustained tones, simple waveforms
  • Experimental sources: Multi-layered mixes, processed sounds, granular textures

Troubleshooting Common Issues

Problem: "Not enough distinct textures found"
Cause: Source too uniform, too few clusters, analysis parameters inappropriate
Solution: Use more varied source material, increase cluster count, adjust grain size
Problem: Processing very slow
Cause: Long source material, many clusters, small grain size
Solution: Use shorter source selections, reduce cluster count, increase grain size
Problem: Output sounds chaotic/unmusical
Cause: Too many clusters, fast morph speed, inappropriate source
Solution: Reduce cluster count, slow morph speed, use more coherent source material
Problem: Memory errors during processing
Cause: Very long output duration, many grains, system memory limits
Solution: Reduce output duration, increase grain size, close other applications