ZigZag Time Effect — User Guide

Alternating forward/back-step time reading with two playback modes: Stutter keeps every extracted grain forward, while Scrub reverses grains taken from backward source positions. Random duration and amplitude variation, extraction windows, and optional grain overlap shape the result.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 0.5 (2026) License: MIT License Repo: GitHub
Contents:

What this does

ZigZag Time Effect repeatedly extracts short grains while moving a source read position through the selected Sound. Processing begins with a forward grain, then alternates between a forward read and a back-step read.

source → forward grain → back-step grain → forward grain → back-step grain → ... → optional overlap between grains → target peak scaling

The source position still progresses overall because both branches advance currentPosition, but the backward branch first chooses a read region behind the current position. Playback_mode determines whether that back-step grain is played forward or reversed.

The script processes a private zero-based copy. The selected original Sound and its time domain remain unchanged.

Quick start

  1. Select exactly one Sound object.
  2. Run ZigZag_Effect.praat.
  3. Choose Default (Tape Scrub), Subtle Stutter, Aggressive Glitch, Tape Wobble, or Custom.
  4. Choose Stutter or Scrub.
  5. Set Direction_changes_per_second and Zigzag_time_s to establish the base grain scale.
  6. Use Forward_ratio and Backward_distance_factor to control movement through the source.
  7. Choose the extraction window and variation amounts.
  8. Set Segment_overlap_s and Max_segments.
  9. Run. The result is named <source>_zigzag_<mode>.

Playback modes

Stutter — always play forward

Forward and back-step grains are both extracted from the source and played in their original direction. The zigzag comes from changes in source position: the backward branch moves the next extraction region behind the current read position, but the grain itself still runs from its lower time to its higher time.

Scrub — reverse when moving back

The source-position logic is the same, but every backward grain is reversed after extraction. The alternating sequence therefore contains true forward and reverse playback:

Forward grain: play startTime → endTime Backward grain in Scrub: extract startTime → endTime then Reverse play endTime → startTime

The Default, Aggressive Glitch and Tape Wobble presets use Scrub. Subtle Stutter uses Stutter.

Timing & source movement

Base grain duration

baseDuration = 1 / Direction_changes_per_second if baseDuration > Zigzag_time_s: baseDuration = Zigzag_time_s / 2

Zigzag_time_s therefore acts as a limit on the base grain scale. When 1 / Direction_changes_per_second is already shorter, Zigzag_time_s does not change the base duration.

Per-grain duration

safeVariation = min( Segment_duration_variation, 0.99 ) grainDuration = baseDuration × Uniform( 1 - safeVariation, 1 + safeVariation )

Every generated duration remains positive.

Forward branch

startTime = currentPosition endTime = min( currentPosition + grainDuration, sourceDuration ) currentPosition += grainDuration × Forward_ratio

Backward branch

backwardDistance = grainDuration × Backward_distance_factor startTime = max( 0, currentPosition - backwardDistance ) endTime = startTime + grainDuration

If the backward read would exceed the source end, the extraction window is moved left so the requested duration fits whenever possible.

After every backward grain:

currentPosition += grainDuration × Forward_ratio × 0.3

The alternating branches therefore use different forward-progress rates: the backward branch advances the read position at 30% of the corresponding forward-branch rate.

Extraction windows, variation & overlap

Window type

Each grain is created directly with Praat Extract part using the selected window:

Window_typePraat extraction window
HanningHanning
HammingHamming
RectangularRectangular

The selected extraction window supplies the grain-edge shaping.

Amplitude variation

safeAmplitudeVariation = min( Amplitude_variation, 0.99 ) gain = Uniform( 1 - safeAmplitudeVariation, 1 + safeAmplitudeVariation ) grain = grain × gain

One random gain is drawn independently for every grain and applied equally to all of its channels.

Overlap

After all grains have been generated, they are assembled in one batch. With a positive overlap the script uses Concatenate with overlap.

effectiveOverlap = min( Segment_overlap_s, 0.99 × shortestActualGrainDuration )

This keeps the requested overlap below the duration of every generated grain. With zero overlap, ordinary Concatenate is used.

Presets

PresetModeZigzag timeForward ratioOverlapChanges/sBack factorDuration var.Amp var.
Default (Tape Scrub)Scrub0.05 s0.602 ms200.800.150.10
Subtle StutterStutter0.08 s0.753 ms120.500.080.05
Aggressive GlitchScrub0.03 s0.501 ms351.200.250.20
Tape WobbleScrub0.12 s0.655 ms80.600.120.08

Named presets overwrite only the values shown above. They do not change Window_type, Max_segments, Scale_peak, Draw_visualization, or Play_result.

Parameters & effective limits

ParameterDefaultExact role
PresetDefault (Tape Scrub)Four named presets plus Custom.
Playback_modeScrubStutter keeps backward-position grains forward; Scrub reverses them.
Zigzag_time_s0.05 sUpper constraint used when the reciprocal direction-change duration is larger; must be shorter than the source.
Forward_ratio0.6Controls forward movement of the source read position; positive form field with no internal upper clamp.
Segment_overlap_s0.002 sRequested final grain overlap; capped to 99% of the shortest actual grain.
Direction_changes_per_second20Natural number; establishes 1/rate base duration before the Zigzag_time_s limit.
Backward_distance_factor0.8Multiplies current grain duration to determine how far behind currentPosition a backward extraction begins.
Window_typeHanningHanning, Hamming, or Rectangular extraction window.
Segment_duration_variation0.15Uniform per-grain duration variation; effective maximum 0.99.
Amplitude_variation0.10Uniform per-grain gain variation around 1; effective maximum 0.99.
Max_segments500Hard maximum number of generated grains.
Scale_peak0.91Final target Sinc70 peak for every non-silent result.
Draw_visualizationOnDraw shared-scale waveforms, read-head trajectory and summary.
Play_resultOnPlay the completed result.
There is no random-seed control in v0.5. Grain durations and amplitude factors are newly randomized on each run.

Channels & output duration

Channel handling

The private processing copy keeps the complete channel layout of the selected Sound. Extraction, reversal, amplitude scaling and concatenation therefore preserve mono, stereo, or higher multichannel channel count.

All channels of a grain share the same source-time region, reversal decision and amplitude factor.

Output duration

Output duration is determined by the actual grain durations and the final effective overlap:

outputDuration ≈ sum(actual grain durations) - effectiveOverlap × (segmentCount - 1)

The result is not constrained to the source duration.

Max_segments stop

The processing loop ends when either:

If the segment cap is reached first, the zigzag read does not continue through the remaining source timeline.

Final peak scaling

After concatenation, the script measures the Sinc70 absolute extremum. Every non-silent result receives:

Scale peak: Scale_peak

This is target peak normalization. A non-zero result below the requested peak can therefore be amplified as well as attenuated. Digital silence is left unchanged.

Visualization

The v0.5 Picture view contains:

  1. Source waveform — display-only mono fold when the input has more than one channel.
  2. Zigzag output waveform — display-only mono fold when the result has more than one channel.
  3. Read-head trajectory — x = source position, y = output order.
  4. Summary strip — preset, mode, segment count, direction-change rate, forward ratio, backward distance, effective overlap, input duration and output duration.

Shared waveform scale

Source and output use one common amplitude range derived from the larger absolute peak with 12% headroom. Their displayed heights are therefore directly comparable.

Read-head trajectory

The trajectory visualizes the actual playback path rather than only extraction blocks:

For very large renders, the visualization samples the trajectory at a display step derived from the segment count; the DSP still uses every generated grain.

Output behavior