Tournament Grid Recomposer — Concatenative Sequencing

Metric-constrained concatenative recomposition by tabu-filtered tournament selection. A segment re-ordering sequencer that cuts a mono pool, tags each segment with features (metric phase, pitch, centroid, RMS), and fills an output grid using cost-based tournament selection with tabu memory.

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

What this does

This script implements a metric-constrained concatenative recomposition engine. A mono segment pool is cut from the source, each segment is tagged with a measured feature vector (phi = metric phase, F0 = pitch, C = spectral centroid, E = RMS level), and an output grid of measures × steps-per-measure slots is filled one slot at a time using tabu-filtered tournament selection.

What is a "metric phase"? The metric term is an alignment preference, not a beat tracker. phi is measured against a grid the user declares (Target_BPM, time signature, downbeat offset). If the source is not actually at that tempo, phi is still well defined but it no longer means "where this material sat in a bar." Grid segmentation makes the tagging tautological by construction; onset and fixed-window segmentation do not.

Key Features:

Unvoiced PSOLA handling (v0.3): Compressing unvoiced material is transparent; expanding it duplicates grains and injects periodicity into noise. The script allows unvoiced compression unconditionally, but caps unvoiced expansion at Unvoiced_max_stretch_ratio (default 1.1). Unvoiced expansion beyond this cap is skipped — the natural material is kept and the slot zero-padded. This is counted and reported as "unvoiced expansion skipped."

Quick start

  1. In Praat, select exactly one Sound object.
  2. Run script…Tournament_Grid_Recomposer.praat.
  3. Choose Segmentation_method (Grid / Onsets / Fixed Window).
  4. Set Target_BPM, Time_signature_numerator, Subdivision (quarter/eighth/sixteenth).
  5. Set Tournament_size_k (candidates per slot) and Tabu_history_length.
  6. Adjust feature weights: metric phase, pitch, spectral centroid, energy.
  7. Select Weight_mode (Renormalized acoustic weights or Literal spec formula).
  8. Click OK — the script segments, tags, runs tournaments, resynthesises, and creates output.
Quick tip: Use Grid/Quantized Beats for tempo-aligned recomposition — the metric phase constraint will favour segments that start on grid positions. Use Onsets/Transients for rhythm-driven segmentation. Increase Tournament_size_k (5–10) to tighten the metric phase alignment. Enable Tabu memory to avoid repeating the same segment within the last N slots. The visualisation shows the selection path and cost trace.
Important: This script is a segment re-ordering sequencer, not a spectral process. It does not create new spectral content — it reorders existing segments from the source. The metric phase is circular: d = min(|phi_i - phi_t|, 1 - |phi_i - phi_t|). If the source is not at the declared tempo, the metric term will still work but it will no longer mean "beat alignment." The selection is stochastic — set Random_seed for reproducibility (0 = clock-derived seed).

3 Segmentation Modes

Grid / Quantized Beats

Segments are cut on the subdivision grid declared by Target_BPM, Time_signature, and Subdivision. The downbeat offset shifts the grid. This mode makes the metric phase tagging tautological — every segment starts exactly on a grid point.

Use: When the source is already tempo-aligned, or when you want to enforce strict metric alignment.

Onsets / Transients

Segments are cut at intensity onsets (local maxima of energy rise). The threshold controls sensitivity; min IOI prevents too many cuts.

Use: For rhythmically varied material where transients define the natural segmentation.

Fixed Window

Segments are cut at a fixed interval (ms). Simple, predictable, independent of content.

Use: For uniform segmentation when neither grid nor onset detection is suitable.

Fallback behaviour: If onset detection finds fewer than 4 segments, the script falls back to fixed-window segmentation (reported in the Info window). This prevents the pool from being too small for meaningful tournament selection.

Tournament Selection — Cost Function

Cost per candidate

Cost_metric = circular distance( phii , phitarget ) × 2

Cost_acoustic = normalized weighted distance from the previously placed segment:

wp·|dF0| + wc·|dC| + we·|dE|

Cost_total = wphi × Cost_metric + (1 - wphi) × Cost_acoustic

Acoustic weights are renormalized

In Renormalized mode, the three acoustic weights are normalised to sum to 1 before the (1 - wphi) scaling is applied. This ensures that the effective weights match what you typed. In Literal spec mode, the spec formula is preserved exactly.

Missing F0 handling

If either side of a candidate transition is unvoiced, the pitch term is omitted and the remaining acoustic weights are rescaled locally. This prevents unvoiced segments from being artificially cheap because they lack a pitch dimension. Known asymmetry: voiced and unvoiced candidates in the same tournament are scored in different feature spaces — this is deliberate, documented, and alters the selection outcome.

Tabu memory: The Tabu_history_length most recently used segments are excluded from the candidate pool. This prevents immediate repetition and encourages variety. If the pool is exhausted, the tabu queue is relaxed (counted and reported).

4 Features per Segment

Metric phase φ

Position inside a measure, in [0, 1). Computed from the segment's start time relative to the declared grid and downbeat offset. Circular distance is used — phase 0.98 is 0.02 of a bar early, not 0.98 away.

Pitch F0 (Hz)

Mean fundamental frequency from Praat's Pitch analysis. Unvoiced segments have no F0 — the pitch term is omitted when either side is unvoiced.

Spectral centroid C (Hz)

Centre of gravity of the spectrum — brightness. Extracted from a windowed (Hanning) segment to avoid edge energy bias.

RMS level E (dB)

Root-mean-square amplitude in decibels. Loudness/dynamics proxy.

Feature normalisation: All features are min-max normalised to [0, 1]. A flat feature (constant across the pool) collapses to 0.5 and contributes no preference (reported in the Info window). This prevents a constant feature from dominating the cost function.

Applications

Metric-constrained recomposition

Use case: Reorder a sound to follow a metric grid — create a rhythmic recomposition from a non-rhythmic source.

Settings: Grid segmentation, Target_BPM set to the desired tempo, metric phase weight high (0.6–0.8). The output will place segments on the grid.

Onset-driven reordering

Use case: Use the natural transients of the source as segmentation points, then reorder them according to metric and acoustic continuity.

Settings: Onsets segmentation, moderate metric weight (0.3–0.5), higher acoustic weights for continuity.

Stochastic texture generation

Use case: Generate a new texture from a source by random selection with continuity constraints.

Settings: Fixed window segmentation, tournament k=1 (uniform random), tabu memory on. The output is a random walk through the source's segments with tabu avoiding immediate repeats.

Workflow: Voice recording → Grid-aligned recomposition

Source: Spoken word or sung phrase.
Settings: Grid segmentation, 120 BPM, 4/4, sixteenth notes, metric weight=0.6, k=5.
Result: The voice is recomposed into a grid-aligned sequence — syllables land on the beat grid, creating a rhythmic pattern.

Workflow: Drum loop → Onset-driven remix

Source: Drum loop.
Settings: Onsets segmentation, threshold=3 dB, metric weight=0.4, k=7.
Result: The drum hits are reordered according to metric phase and acoustic continuity — a new rhythmic pattern from the same source.

Workflow: Ambient texture → Stochastic walk

Source: Long ambient texture.
Settings: Fixed window (200 ms), tournament k=1, tabu length=5, all weights zero (flat cost).
Result: A random walk through the texture — segments are selected uniformly at random, with tabu preventing immediate repeats.

Troubleshooting:
Mean metric-phase error is high (>0.2): Increase Tournament_size_k (5–10) or increase the metric phase weight. The random-draw baseline is reported — the tournament's improvement over random is the key metric.
Many slots are zero-padded: The source may be too short for the requested output length, or unvoiced expansion was skipped (reported as "unvoiced expansion skipped"). Increase the source duration or reduce Output_measures.
Cost trace is flat: All weights may be near zero (flat cost). The selection becomes uniform random — reported as "flat cost" in the warnings. Increase feature weights or adjust the weights.
PSOLA-stretched slots are few: The source segments may already match the grid step length (ratio ≈ 1). Or the segments are too short for PSOLA (needs at least 3/pitch_floor seconds).
Immediate repeats are high: Increase Tabu_history_length or reduce k (fewer candidates → more repeats). The immediate repeats count is reported in the summary.

Visualisation (4-panel mechanism view)

When Draw_visualization is enabled, the script generates:
  • Panel A (Pool): Source waveform with grey measure lines and red segment cuts. Shows the segmentation and grid alignment.
  • Panel B (Selection): Output slot vs source segment — blue dots show which segment won each slot. Grey vertical lines are measure boundaries in the output.
  • Panel C (Cost): Winning cost (blue line) with grey band showing the min–max cost range in each tournament. Red line = mean winning cost.
  • Panel D (Grid Check): Rendered output waveform with grey measure lines. Visual check of grid alignment and amplitude.
  • Summary bar: BPM, time signature, slots, pool size, k, tabu length, weights, coverage, PSOLA stats, seed.
The Selection panel (B) is the key diagnostic: it shows the read-head path over the source — a flat line means the same segment was reused; a scattered path means varied selection.