Wave Gesture Path Performer — Wearable Timbral-Path Performance

Turn a folder of sounds into a gesturally playable timbral path. The script orders the corpus by MFCC similarity, captures Tilt, Pan, and Roll from a Genki Wave ring over BLE-MIDI, and renders the recorded gesture as an overlapping polyphonic traversal through the corpus.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 1.8 (2026) Category: Hybrid Systems License: MIT License Repo: Praat AudioTools
Contents:

What this does

Wave Gesture Path Performer transforms a folder of audio files into a performable timbral space. Rather than assigning gestures directly to arbitrary file numbers, the script first analyses the corpus with MFCCs and constructs a nearest-neighbour path through timbrally related sounds. A recorded Wave-ring gesture then moves through that ordered path and controls how successive voices are selected and shaped.

What makes this different? This is not a conventional sample selector. Position 5 on the performance path is not simply the fifth file in the folder: it is the fifth point on an MFCC-based nearest-neighbour trajectory. The performer's body therefore navigates an acoustically organised corpus rather than a filename list.

Key Features:

Quick start

  1. Pair the Genki Wave ring as a BLE-MIDI device and make sure it appears as a MIDI input port.
  2. Install the Python MIDI dependencies: mido and python-rtmidi.
  3. Place wave_capture.py in plugin_AudioTools/py/.
  4. Run Wave_Gesture_Path_Performer.praat.
  5. Choose a folder containing at least two supported audio files.
  6. For a first run, keep Tilt mapping = Auto-fit take to full corpus, Grain seconds = 0.25, Voice seconds = 1.5, and Pan scrub amount = 4.
  7. Click Start. After the countdown, move the ring until the low end-beep.
  8. The rendered take appears in the Praat Objects list as Wave_Take_1, Wave_Take_2, and so on.
Good corpus design: use several contrasting but compositionally related sounds. The tool is especially effective when the corpus contains enough timbral diversity for the MFCC path to become perceptually meaningful, while still retaining local continuity between neighbours.

How it works

1. The corpus is loaded and normalised

The script scans the selected folder for supported audio files, loads each file as a Praat Sound, converts multichannel files to mono, and resamples all successfully loaded sounds to the sample rate of the first valid corpus item.

2. MFCC mean vectors describe timbral similarity

Each sound is analysed with 12 MFCC coefficients using a 15 ms analysis window and 5 ms time step. The mean value of each coefficient across time becomes the sound's compact timbral descriptor.

3. A nearest-neighbour timbral path is constructed

Euclidean distances are calculated between the MFCC mean vectors. Starting from the first loaded sound, the script repeatedly chooses the nearest unvisited sound until every corpus item has been placed on a single ordered path.

corpus files ↓ MFCC mean vectors ↓ pairwise timbral distances ↓ nearest-neighbour path ↓ Wave gesture traversal ↓ polyphonic rendered Sound

4. Python captures the wearable gesture

Praat launches wave_capture.py, which opens the Wave MIDI port, records the configured CC streams at approximately 100 Hz, and writes a temporary tab-separated gesture file containing time, tilt, pan, and roll.

5. Praat renders the take

At each trigger time, the gesture is sampled, mapped to a corpus-path position, and used to select a source sound. A Hanning-windowed excerpt is extracted and summed into an output buffer. Overlapping excerpts form a polyphonic texture whose trajectory is determined by the recorded hand movement.

Gesture mapping

Tilt — global path position

Tilt chooses the main location along the MFCC-ordered corpus path.

Musical role: large-scale movement through timbral space.

Pan gesture — local scrub

Pan adds a positive or negative offset around the Tilt-selected position. The amount is limited by Pan scrub amount.

Musical role: local deviation, reversal, and non-linear movement around the current timbral region.

Roll — velocity / volume

Roll is mapped to voice amplitude between the internal minimum level and full scale.

Musical role: dynamic articulation and emphasis.

Two scales of navigation. Tilt supplies the global position in the corpus, while Pan remains a local scrub around that position. This separation makes it possible to travel broadly through the timbral path without losing fine gestural control over neighbouring sounds.

Controls

ControlDefaultFunction
FolderBlankCorpus folder. Leave blank to choose a folder with a dialog.
Record seconds8.0 sDuration of each captured gesture take.
Countdown seconds3Preparation time before recording begins. Audible cues mark countdown, start, and finish.
Grain seconds0.25 sTime between triggers. Smaller values create denser activity and more frequent corpus changes.
Voice seconds1.5 sMaximum duration of each triggered excerpt, limited by the duration of its source Sound.
Max voices8Maximum number of simultaneously active voices before oldest-voice stealing is applied.
Pan scrub amount4 positionsMaximum local path displacement created by the Pan gesture.
Tilt mappingAuto-fit take to full corpusChooses between take-relative full-range mapping and fixed absolute 0-1 mapping.
Auto playOnPlays the rendered take after it is created.

Tilt mapping

Auto-fit take to full corpus

The script measures the take's own Tilt range using the 2nd and 98th percentiles and stretches that robust range across corpus positions 1...n.

Use: ensures that a natural hand gesture can access the full timbral path even when the physical sensor does not use the complete MIDI range.

Absolute (0-1)

The raw normalized Tilt value is mapped directly onto the corpus path.

Use: stable physical correspondence across takes, useful when the Wave already covers most of its MIDI range or when repeatable positions matter more than full-range access.

Auto-fit safety: if the robust Tilt range is smaller than 0.02, the script treats the take as having insufficient Tilt movement and falls back to Absolute mapping rather than amplifying near-static sensor noise.

Corpus loading

Version 1.8 explicitly validates the corpus before any gesture is recorded.

BehaviorDetails
Supported formats.wav, .aif, .aiff, .aifc, .flac, and .mp3, case-insensitive.
Folder depthOnly files directly inside the selected folder are searched. Subfolders are counted and reported but are not traversed.
Load validationEvery file is checked to confirm that a new Sound object was actually created. Failed loads are reported instead of accidentally reusing the previously selected Sound.
Minimum corpus sizeAt least 2 successfully loaded sounds are required. The script stops before recording if a performable path cannot be constructed.
Sample rateAll corpus Sounds are converted to the sample rate of the first successfully loaded item.
ChannelsMultichannel corpus files are converted to mono for path analysis and rendering.
If the result seems to play only one sound: check the Info window first. It reports both Audio files found and Loaded sounds. A corpus of one successfully loaded sound cannot produce meaningful path traversal, and v1.8 now stops before recording in that situation.

Visualisation

After each take, the script produces a Praat Picture display organised as a compact explanation of the performance:

Gesture

Shows normalized Tilt, Pan, and Roll over time. In Auto-fit mode, the shaded region identifies the robust Tilt range fitted to the corpus.

Path

Shows the corpus position selected at every trigger. Grey indicates the position derived from Tilt alone; orange shows the position actually played after Pan scrub. Dot size reflects Roll-controlled volume.

Rendered take

Shows the final waveform together with trigger onsets, making the relationship between gesture density and resulting sound explicit.

The summary strip is diagnostic as well as descriptive. It reports corpus size, MFCC ordering, performance settings, Tilt mapping, path coverage, MIDI configuration, captured sample count, take duration, and output object name.

MIDI diagnostics

The Python helper records all incoming MIDI activity during each take, not only the three configured control streams. The Info window therefore shows which CC numbers actually arrived, their value ranges, message counts, and MIDI channels.

Detected CC activity (this take):
  CC 2:   25-126   (357 messages, ch 1)  <- Pan
  CC 1:    0-126   (317 messages, ch 1)  <- Tilt
  CC 3:    0-126   (239 messages, ch 1)  <- Roll

If a configured control shows too few messages or too little movement, the helper issues a warning and reports other active CCs. It does not remap controls automatically; the user remains in control of the Wave / Softwave configuration.

Additional Wave data: other active CC streams may appear in the report even though v1.8 does not map them to sound. They are intentionally left unused rather than silently assigned to a musical parameter.

Technical behavior

Requirements & installation

Python dependencies required: mido and python-rtmidi.

Install with:
python -m pip install mido python-rtmidi
ComponentRequirement
PraatPraat with scripting support for external system calls. Praat 7 may ask for full trust because the tool launches Python and creates/deletes temporary files.
PythonPython 3. The frontend uses the library's OS-specific Python discovery convention.
Python helperPlace wave_capture.py in plugin_AudioTools/py/. The script also accepts the helper inside the selected corpus folder as a fallback.
Genki WaveWave ring paired as a BLE-MIDI input device. Default gesture CCs are Tilt = 1, Pan = 2, Roll = 3.
Softwave / MIDI configurationThe ring must send the intended movement streams as MIDI CC data. The helper's activity report can be used to verify the actual CC numbers and ranges.

Limitations

Offline audio rendering. The Wave gesture is captured during the take, but the final Sound is rendered after capture. This is not a real-time audio synthesizer or live neural instrument.

Outputs

Each completed take remains in the Praat Objects list as:

Wave_Take_1
Wave_Take_2
Wave_Take_3
...

The script does not save an audio file automatically. The user can audition, inspect, rename, edit, or save any take from Praat after the session.

Session workflow: after every take, the script offers either Stop or another take. The corpus is analysed only once at the beginning of the session; subsequent takes reuse the same MFCC-ordered path.

Applications

Embodied corpus navigation

Use case: perform a corpus by moving through a timbrally ordered path rather than selecting files manually or triggering fixed pads.

Gestural timbre improvisation

Use case: use broad Tilt motion for structural traversal while Pan creates local detours and Roll shapes articulation and dynamics.

Performance-derived offline composition

Use case: record physically expressive takes, then treat the resulting Wave_Take_N objects as fixed compositional material for further Praat AudioTools processing.

Timbral-path exploration

Use case: use the body as an exploratory interface for hearing how an MFCC similarity ordering behaves across heterogeneous instrumental, environmental, percussive, or textural corpora.

Research on embodied sound control

Use case: study the relationship between wearable gesture, corpus-space navigation, and rendered sound while retaining the captured MIDI trajectory and an explicit visual account of the mapping.

Workflow: heterogeneous corpus → gestural timbral traversal

Corpus: 10-30 contrasting short sounds.
Settings: Auto-fit Tilt, Grain 0.25 s, Voice 1.5 s, Pan scrub ±4 positions.
Performance: use Tilt for broad travel, Pan for local perturbation, and Roll for dynamic emphasis.
Result: an overlapping offline-rendered texture whose succession follows a recorded embodied path through MFCC-organised sound space.