Granular Navigation Engine — User Guide
A corpus-based granular navigation tool that analyzes a folder of audio, learns a compact acoustic embedding, generates a path through selected grains, and reconstructs that path in Praat as mono or latent-positioned stereo.
What is this?
Granular Navigation Engine treats a folder of recordings as one searchable corpus of overlapping audio grains. Python measures each grain, learns a 16-dimensional latent representation with an autoencoder, and chooses a sequence of unique grains according to the selected navigation mode. Praat then returns to the source files and rebuilds that sequence from the original audio regions.
Choose a folder, choose how you want to move through its acoustic space, and the tool constructs a new sound by following that path through grains drawn from the corpus.
The learned representation is used to organize and navigate the corpus. It does not synthesize new spectral content: the final sound is assembled from extracted regions of the source recordings.
Complete pipeline
Corpus and grain construction
Files
The Python engine scans the selected folder itself. It reads supported audio files located directly in that folder; it does not recursively scan subfolders. Supported extensions are .wav, .aif, .aiff, and .flac. Files are processed in sorted filename order.
Analysis grains
Each file is divided into grains with a hop equal to 50% of the grain duration. A final partial grain is accepted when at least 20 ms of source audio remains. For feature extraction, a short final grain is zero-padded to the nominal grain size, while its stored end time still marks the real end of the source material.
hop duration = 0.5 × grain duration
Channel used for analysis
Multichannel files are normally analyzed as the arithmetic mean of their channels. Before committing to that mean, the engine compares its whole-file RMS with the strongest individual channel. If the mean falls below 10% of the strongest-channel RMS, the engine uses that strongest channel instead. This phase-safe fallback avoids analyzing a nearly cancelled channel sum.
The chosen policy is stored for each grain so Praat can use the corresponding mono representation again during reconstruction.
Acoustic feature space
Each grain is represented by 14 features:
| Feature | Implementation |
|---|---|
| 8 spectral-band energies | Eight broad bands with linearly spaced frequency boundaries from 80 Hz to 8 kHz, or to just below Nyquist at lower sample rates; log-energy is stored for each band. |
| Spectral centroid | Power-weighted spectral centre in Hz. |
| Spectral spread | Power-weighted spread around the centroid. |
| Spectral flatness | Geometric-to-arithmetic power ratio. |
| Spectral rolloff | Frequency below which 85% of spectral power is accumulated. |
| Zero-crossing rate | Fraction of adjacent sample pairs that cross or leave zero/sign. |
| RMS | Root-mean-square amplitude of the analysis grain. |
A Hann window is applied for FFT-based spectral measurements. Before learning, each feature dimension is normalized by its corpus median and interquartile range:
Learned embedding
The normalized 14-D feature vectors train a compact feed-forward autoencoder. Its encoder maps each grain through 64 and 32 hidden units to a 16-dimensional latent vector. The decoder learns to reconstruct the original normalized feature vector from that latent representation.
The Praat wrapper uses a fixed 80 training epochs and seed 42. The seed stabilizes the intended stochastic choices for repeat runs in the same software environment, while exact numerical identity across different hardware or library builds should not be assumed.
PCA projection
After the latent embedding is ready, Python calculates a two-dimensional PCA projection. These two PCA coordinates are written to the path CSV. They serve two roles:
- Visualization: Praat draws the selected path in the 2-D projection.
- Stereo rendering: PCA dimension 1 supplies the latent left/right coordinate when Stereo output is enabled.
Navigation modes
The path contains each chosen grain at most once. Already visited grains are removed from the candidate set, so the requested path cannot exceed the number of available grains.
| Mode | How the next grain is chosen |
|---|---|
| Similarity | Chooses the unvisited grain nearest to the current grain in the full 16-D learned latent embedding. |
| Smooth | Chooses the unvisited grain nearest to the current grain in the normalized 14-D acoustic feature space. |
| Contrast | Chooses the grain farthest in latent space from the mean of the recent path history. |
| Brighter | Biases the path toward increasing spectral-centroid character while retaining transition continuity. |
| Darker | Biases the path toward decreasing spectral-centroid character while retaining transition continuity. |
| Noisier | Biases the path toward higher zero-crossing-rate character. |
| Harmonic | Biases the path toward lower spectral flatness. |
| Denser | Biases the path toward higher RMS amplitude. |
| Sparser | Biases the path toward lower RMS amplitude. |
Starting point
Similarity, Smooth, and all six directional modes begin at the grain closest to the centre of the 16-D latent embedding. Contrast begins from a seeded random grain.
How directional navigation works
For Brighter, Darker, Noisier, Harmonic, Denser, and Sparser, the engine learns a direction inside latent space that predicts the chosen acoustic feature. Candidate grains then receive two components:
The transition component is:
This makes the directional modes biased trajectories rather than strict monotonic ramps. A Brighter path, for example, favors the latent direction associated with higher centroid while still rewarding a coherent transition from the current grain.
Latent stereo rendering
When Stereo output is enabled, Praat constructs stereo from the mono reconstruction grain by grain. The original stereo or multichannel image of the source recordings is therefore not preserved.
PCA X → panorama
PCA dimension 1 (emb_x) provides the target panoramic position. The normalization uses the larger absolute X extent of the entire corpus PCA projection, not just the selected path. PCA zero therefore stays at acoustic centre.
If no usable PCA-X range is available, the stereo result remains centred.
Spatial inertia
The first grain begins exactly at its latent target. Each later grain smooths the target using the previous panoramic position:
An inertia of 0 follows every latent point directly. Larger values retain more of the previous position and therefore slow panoramic movement. Custom inertia is constrained to 0–0.98.
Equal-power panning
The smoothed position is converted to an angle from 0 to π/2:
Left gain = cos(angle)
Right gain = sin(angle)
This is an equal-power left/right mapping. The spatial layer is applied only after Python has already generated the navigation path; changing the spatial preset does not alter feature analysis, embedding, or grain selection.
Spatial presets
Spatial presets set Width and Inertia together. The manual Width/Inertia fields are used only when Custom is selected.
| Preset | Width | Inertia | Pan character |
|---|---|---|---|
| Latent Walk | 0.85 | 0.35 | Broad latent movement with moderate smoothing. |
| Subtle Drift | 0.45 | 0.60 | Narrower panorama with stronger continuity. |
| Wide Flow | 1.00 | 0.55 | Full width with a flowing, smoothed trajectory. |
| Active Roam | 1.00 | 0.20 | Full width with faster response to latent changes. |
| Maximum Motion | 1.00 | 0.00 | Direct full-width mapping with no inertial smoothing. |
| Slow Panorama | 1.00 | 0.85 | Full possible width but strongly smoothed movement. |
| Custom | 0–1 | 0–0.98 | Uses the values entered in the manual fields. |
Praat reconstruction
Python writes the selected source filename and original start/end time for each path grain. Praat then reconstructs the result in path order using a bounded-memory loop: it opens the current source, extracts the needed grain, appends it to the growing result, and releases temporary objects before continuing.
Mono source used for reconstruction
- Mono source files remain mono.
- Normal multichannel files are converted to mono for reconstruction.
- If Python selected a phase-safe representative channel for a file, Praat extracts that same channel instead of averaging the channels.
Thus all navigation reconstruction is based on one mono stream per grain. Stereo, when requested, is created afterward from latent position.
Mixed sample rates
The first successfully reconstructed grain establishes the output sampling frequency. Any later grain from a different sampling rate is resampled by Praat to that frequency before extraction/concatenation continues.
Extracted duration
Praat clamps every path interval to the real source duration and accepts it when at least 5 ms remains. The region is extracted with a rectangular window. The final partial analysis grain is therefore reconstructed only for its real source duration rather than with the zero padding used during feature analysis.
Crossfade
Each new grain is appended with Praat Concatenate with overlap. The requested overlap is:
This overlap is part of the output construction: successive source grains overlap in time instead of being butt-joined.
Final level
After assembly, Praat applies Scale peak: 0.92 to the completed Sound. This is target peak normalization, not an attenuate-only ceiling.
Controls
| Control | Meaning |
|---|---|
| Folder | Corpus folder. Leave blank to choose the folder with a Praat dialog. |
| Navigation mode | Selects the path-generation rule described above. |
| Grain_ms | Nominal analysis grain duration. The Python engine constrains effective analysis size to 25–500 ms; use this range for consistent settings. |
| Path_length | Requested number of unique path grains. Python constrains the request to 4–1000 and then to the number of grains actually available. |
| Stereo_output | On: create latent-positioned stereo. Off: leave the reconstructed result mono. |
| Spatial_preset | Chooses a paired Width/Inertia setting. |
| Spatial_width | Custom maximum excursion from centre, constrained to 0–1. Used only with Custom. |
| Spatial_inertia | Custom one-pole smoothing amount, constrained to 0–0.98. Used only with Custom. |
| Draw_visualization | Draws the path analysis figure in the Praat Picture window. |
| Play_result | Plays the final Sound when processing is complete. |
Persistent analysis and embedding cache
The Python engine uses a two-level persistent cache by default under:
~/.praat_audiotools/gne_cache
Analysis cache
Decoded feature analysis is reused when the corpus signature and analysis configuration are unchanged. The cache key includes the folder, top-level audio filenames, file sizes and modification timestamps, grain/hop duration, feature schema, and relevant NumPy/soundfile versions.
Embedding cache
The trained 16-D embedding and PCA projection are cached separately. Its key additionally includes training epochs, seed, latent dimension, and relevant PyTorch/NumPy versions.
An unreadable cache entry is ignored and recomputed. Failure to create the cache directory disables caching rather than stopping the analysis.
Visualization
When enabled, the Praat Picture window summarizes the selected path rather than drawing the entire corpus.
1. Grain timeline
Each path step is a colored block representing its source file. Up to eight source identities are assigned distinct palette entries for the display.
2. Transition-score curve
The curve shows the latent transition similarity written for each selected edge. Higher values mean smaller 16-D latent distance between consecutive grains:
The final row has no following transition, so its stored transition score is 0.
3. Embedding path
The selected grains are plotted in the 2-D PCA projection and connected in navigation order. Source-file colors match the timeline. The first selected point is marked in green and the last in red.
The plotted limits are based on the selected path. Stereo panning, however, uses the whole-corpus PCA-X reference range written by Python.
4. Mode strip
A colored strip labels the active navigation mode.
5. Summary panel
The summary reports corpus grains, number of source files, mode, phase-safe fallback count, latent dimension, epochs, path length, Python runtime, grain/hop settings, crossfade, and the active spatial preset or mono mode.
Output, naming, and temporary files
Sound name
For mono output:
GNE_<mode>_<assembled-grains>gr
For stereo output:
GNE_<mode>_<assembled-grains>gr_stereo
The number in the name is the number of grains successfully assembled by Praat, which can be lower than the requested path length if a source becomes unreadable or a path interval cannot be reconstructed.
Temporary data
The Python path CSV, statistics file, and redirected Python log are temporary and are deleted during normal cleanup. The reconstructed Sound remains in Praat. The persistent Python cache remains available for later runs.
Crash marker
The wrapper writes a persistent diagnostic stage marker to GNE_last_stage.txt in the Praat preferences directory. It records the most recent major lifecycle boundary and is intended to help localize a hard Praat failure.
Interpretive notes
- Corpus-relative representation: normalization, autoencoder training, and PCA are derived from the current corpus. Coordinates and distances should be interpreted within that learned corpus space.
- Directional modes are biases: the six named acoustic directions balance a feature-related latent projection with transition continuity; they do not guarantee a monotonic feature value at every step.
- Harmonic is a flatness proxy: the mode rewards lower spectral flatness; it does not perform harmonic analysis or fundamental tracking.
- Denser/Sparser are RMS proxies: these modes concern grain energy, not note density or rhythmic density.
- PCA is not the navigation space: the 2-D view is a projection of the learned embedding. Similarity and Contrast operate in the full 16-D latent space.
- Original spatial image is replaced: multichannel sources become a mono analysis/reconstruction stream, with optional new stereo created from latent PCA-X position.
- Output duration is path-dependent: it depends on the real extracted grain lengths and the overlap between successive grains.
- Sampling rate follows the first successful grain: later sources are resampled to that rate when required.
Recommended starting point
- Place a small, coherent group of source recordings in one folder.
- Start with Grain_ms = 150 and Path_length = 60.
- Use Similarity to hear movement through the learned latent space, then compare it with Smooth to hear nearest-neighbor movement in the measured acoustic features.
- For stereo, begin with Latent Walk. Use Maximum Motion when you want the most immediate full-width PCA-X mapping.
- Inspect the transition curve and PCA path together with the audio: they show how the selected path moves through the learned corpus representation.