Reich Generator — User Guide

Loop-based auto-phasing in Praat: a static loop is set against a slightly faster drifting copy, with optional pitch transformation, random pitch perturbation, and a static third voice.

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

What this does

Reich Generator selects a short active region from one Sound, turns that region into a repeating mono loop, and builds a stereo texture from two main voices. Voice 1 repeats the loop at its measured duration. Voice 2 may first receive a pitch transformation and Gaussian pitch perturbation, then its playback rate is increased by a precisely calculated ratio so that it completes one extra loop during the requested phase-cycle duration. An optional Voice 3 adds a static unison or octave layer.

What is generated? The final object is a stereo Sound. The left side is based on the static loop and the right side on the drifting loop. When Voice 3 is enabled, the static anchor is combined into both sides. The final stereo result is peak-normalized to 0.99. The source Sound is not modified.

Core behavior:

Quick start

  1. Select exactly one Sound object.
  2. Run Reich_Generator.praat.
  3. Choose one of the four presets, or Manual (Settings below).
  4. Set Total_Duration_min. This parameter is not replaced by the presets.
  5. Set V3_Level_dB_relative if a third voice is used; presets also leave this mix-balance control unchanged.
  6. Use Random_seed = 0 for a fresh random sequence, or a non-zero integer for repeatable random choices.
  7. Leave Create_polar_phase_wheel enabled to draw the process visualization.
  8. Use Play_result to choose whether the final Sound is played automatically.
Preset behavior: A preset replaces the loop range, Voice 2 interval, Voice 3 mode, phase-cycle duration, start-offset mode, and flutter amount. It does not replace V3_Level_dB_relative, Total_Duration_min, Random_seed, or the visualization/playback switches.

What is loop phasing?

Two repeating copies, slightly different loop rates

In this script, “phase” means the relative position of two repeating loop cycles. It is not the instantaneous waveform phase of every frequency component. Voice 1 repeats the selected loop at its original loop duration; Voice 2 repeats a slightly shorter post-drift loop. Their cycle positions therefore move continuously relative to one another.

Let T = measured Voice-1 loop duration Let C = requested phase-cycle duration in seconds N = C / T Drift ratio = (N + 1) / N Voice 2 is assigned an intermediate sampling rate of: source_sample_rate × drift_ratio and is then resampled back to the source sample rate. Result: during approximately C seconds, Voice 2 completes one more loop cycle than Voice 1.
Important distinction: the drift is a real playback-rate change, not pitch-preserving time stretching. It makes the Voice-2 loop slightly shorter and also shifts its pitch by the same small rate ratio. The optional Voice-2 interval transformation is a separate PitchTier/PSOLA operation applied before this rate change.

Start offset

The offset is measured against the actual post-drift Voice-2 loop duration:

Here “50%” or “180°” means half a loop cycle. It does not mean polarity inversion of the waveform and does not imply complete destructive cancellation.

Processing pipeline

1. Source preparation

A private zero-based copy of the selected Sound is created. For multichannel material, the script normally analyzes the channel average. RMS is also measured independently for every channel. If the averaged mono copy falls below 10% of the strongest channel RMS, indicating strong cancellation in the fold-down, the strongest-RMS channel is used instead.

2. Activity-aware loop selection

The loop-duration range is clamped to the available source duration. Candidate duration and start position are drawn uniformly at random. A candidate is accepted when its RMS exceeds the activity floor:

activity floor = min(0.001, 0.05 × whole-analysis-source RMS) minimum numerical floor = 1e-12 maximum attempts = 40

After acceptance, the beginning and end are moved to nearby zero crossings when usable crossings are available. The visualization highlights these final snapped boundaries, not the earlier random candidate.

3. Voice 2: interval, perturbation, drift

If the requested interval is not unison, or if flutter is non-zero, the loop is converted to a Praat Manipulation with a 75–600 Hz pitch-analysis range. PitchTier values are multiplied by the selected interval ratio. Gaussian perturbation is then applied multiplicatively in log-frequency space:

PitchTier value' = PitchTier value × 2^(randomGauss(0, Flutter_Amount_st) / 12)

This parameter is therefore a standard deviation in semitones. It is stochastic pitch perturbation, not a physical model of tape capstan wow/flutter. If the loop contains no voiced PitchTier points, Voice-2 interval and flutter operations have no effect; the script reports this in the Info window.

After PitchTier resynthesis, the exact phase-drift ratio is applied by sampling-rate override followed by resampling.

4. Voice 3: static anchor

Voice 3, when enabled, is derived from the same base loop and does not drift. Octave modes use the same Manipulation/PitchTier mechanism. Its intensity is set relative to the measured base-loop intensity:

V3 target intensity = base-loop intensity + V3_Level_dB_relative

The default is −6 dB relative. If an octave transform is requested but the PitchTier contains no voiced points, the octave transform has no effect.

5. Repeating walls and offset

Each processed loop is concatenated repeatedly and cropped to the required length. Voice 2 is built to Total_Duration + offset before its beginning is removed, so its final duration remains exactly the requested output duration.

6. Stereo mix and final level

With no Voice 3, Voice 1 becomes the left channel and Voice 2 the right channel. With Voice 3 enabled, Praat combines Voice 1 with Voice 3 and converts that pair to mono for the left side; Voice 2 and Voice 3 are combined in the same way for the right side. The two sides are then combined to stereo. Finally, the complete stereo Sound is peak-scaled to 0.99.

Parameters & presets

Form parameters

ParameterDefaultBehavior
PresetClassic ReichFour defined presets plus Manual.
Min_loop_sec0.6Manual minimum candidate duration; must be positive and ≤ Max_loop_sec.
Max_loop_sec1.5Manual maximum candidate duration; clamped to source duration.
V2_IntervalPerfect Fifth (+7st)Manual Voice-2 pitch mode: Unison, +7 st, octave down, octave up.
V3_ModeNoneNone, static unison, static octave down, or static octave up.
V3_Level_dB_relative−6.0 dBVoice-3 intensity target relative to the measured base-loop intensity. Presets do not replace it.
Cycle_Duration_min1.0Manual time for one full relative loop-phase cycle. Must be positive.
Start_OffsetRandomManual initial loop-cycle relationship: 0%, 50%, or random.
Flutter_Amount_st0.05Gaussian PitchTier perturbation standard deviation in semitones; must be ≥ 0.
Total_Duration_min1.0Requested final output duration; presets do not replace it.
Random_seed00 = fresh unpredictable sequence; non-zero = reproducible random choices.
Create_polar_phase_wheelYesDraws the complete process visualization.
Play_resultYesPlays the final Sound after processing.

Preset values

PresetLoop rangeV2V3CycleStartFlutter
Classic Reich (Speech / Unison)0.5–1.0 sUnisonNone1.0 min0%0.00 st
Deep Space (Sub-Bass Shadow)2.0–4.0 sUnisonLow Shadow5.0 min50%0.10 st
Holy Trinity (5th + High Anchor)0.8–1.2 s+7 stHigh Shimmer3.0 minRandom0.02 st
Broken Tape (Flutter + Random Offset)0.4–0.9 sUnisonCenter Anchor1.5 minRandom0.30 st
Cycle versus render duration: the phase-cycle duration and total output duration are independent. For example, a 1-minute output with a 5-minute cycle shows only the first fifth of that phase process.

Visualization

When Create_polar_phase_wheel is enabled, the script draws a process visualization with a deliberately dominant phase wheel and three supporting bands.

Phase wheel

The square inner viewport is set explicitly so the polar geometry remains circular. The angular position is the calculated Voice-2 minus Voice-1 loop-cycle phase. The path radius uses a cosine-derived visual “beating depth”:

beat = 0.5 + 0.5 × cos(relative_phase) radius = 5 + 39 × beat blue end of the colour scale = unison region red end of the colour scale = half-cycle / anti-phase region

This is a process diagram derived from loop-cycle phase. Its radius and colour are not measurements of the rendered waveform amplitude or spectral interference.

Source strip

The original source waveform is drawn in neutral gray. The orange region and boundary lines mark the exact loop retained after zero-crossing snapping. For multichannel sources this panel draws the original Sound, while the loop-analysis signal may be the channel average or, when cancellation protection is triggered, the strongest-RMS channel.

Relative phase trajectory

This panel shows the same calculated relative loop-cycle phase against output time, in degrees. Reference lines mark 0°, 90°, 180°, 270°, and 360°. A blue marker indicates the initial phase and a red marker the final phase. Wrap discontinuities are not connected across the 360°→0° boundary.

Summary

The summary reports the source name, measured loop duration, requested cycle duration, number of unison returns within the render, start-offset mode, Voice-2/Voice-3 modes, flutter amount, final duration, and left/right voice roles.

Output & edge cases

Output naming

The final stereo Sound is named:

<source>_ReichGen_<preset>

Only the final Sound remains selected at completion. Intermediate loop, manipulation, pitch-tier, wall, and mix objects are removed during normal completion.

Randomness and reproducibility

A non-zero Random_seed initializes Praat's predictable generator before the script makes random choices. The seed affects candidate loop selection, Random start offset, and Voice-2 Gaussian pitch perturbations. After all random choices have been made, the script restores Praat's safe/unpredictable random mode so later scripts do not inherit the predictable state.

Short, quiet, silent, and unvoiced sources

Multichannel input

The generated loop is mono even when the source is multichannel. The normal analysis path averages channels. When that average nearly cancels relative to the strongest channel, the strongest-RMS channel is used instead. The final generated result is stereo because the static and drifting walls are assigned to separate output sides.

Level note: the final result is peak-normalized to 0.99. This controls the final peak but does not preserve the source's original absolute level. Voice-3 level is evaluated relative to the extracted loop before the final normalization stage.