Accelerating Polyrhythm — User Guide

Generates stereo polyrhythmic event grids whose shared cycle duration changes from an initial speed to a specified final speed, with optional frequency, amplitude, rhythm, pan, or seeded random evolution.

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

Overview

Accelerating Polyrhythm synthesizes two rhythmic layers — and, in one preset, a true third layer — inside a common sequence of cycles. Each layer subdivides every cycle into its own number of equally spaced beats. For example, a 3:2 setting places three P1 events and two P2 events inside each shared cycle.

The cycle duration can accelerate, remain steady, or decelerate across the piece. The script then renders each event as a short synthesized tone, positions the layers in stereo with constant-power panning, and peak-normalizes the completed stereo result to 0.9.

Terminology: the rhythmic layers do not run as independent free tempi. Their inter-onset intervals are derived from the same current cycle duration. The polyrhythm is therefore a ratio of subdivisions within a shared, evolving cycle.

Quick start

  1. Run Accelerating_Polyrhythm.praat; no input Sound is required.
  2. Choose a preset, or choose Custom to use the values in the form.
  3. For Custom, set the initial cycle duration, number of cycles, beat counts, frequencies, and final speed ratio.
  4. Choose exponential or linear acceleration and, if desired, a morph type.
  5. Set the maximum event-tone duration, attack, decay, waveform, and random seed.
  6. Enable Draw_visualization to inspect the generated event lattice, IOIs, and active transformation.
  7. Run the script. The output is a stereo Sound named from the rendered ratio, such as AccelPoly_3v2.

Timing & acceleration

Acceleration_factor is the total end-speed / start-speed ratio. It is not multiplied again on every cycle.

Interpretation: values greater than 1 accelerate, 1 keeps a constant cycle speed, and values between 0 and 1 produce deceleration.

For cycle c, progress is:

p = (c - 1) / (Total_cycles - 1)

with p = 0 when only one cycle is requested. The speed factor is:

Exponential: speed = Acceleration_factor ^ p
Linear:      speed = 1 + (Acceleration_factor - 1) * p

cycle_duration = Base_duration_s / speed

Thus the first cycle always has speed factor 1.0, while the final cycle reaches Acceleration_factor.

Target total duration

If Target_total_duration_s is greater than zero, it overrides the entered initial cycle duration. The script solves the initial duration so that the sum of all cycle durations follows the selected acceleration law and equals the target:

Base_duration_s = Target_total_duration_s / sum(1 / speed[c])

A target value of 0 leaves Base_duration_s in control.

Beat placement

Within each cycle, each layer is evenly subdivided:

P1 IOI = cycle_duration / P1_beats
P2 IOI = cycle_duration / P2_beats
P3 IOI = cycle_duration / P3_beats   (triple-layer preset only)

The next cycle starts immediately after the current cycle duration, so the acceleration law changes the actual event spacing from cycle to cycle.

Presets

Presets replace the central pattern, cycle, acceleration, morph, and waveform settings shown below. Target_total_duration_s, Random_seed, Play_result, and Draw_visualization remain independently user-controlled. Most presets also leave the form's attack, decay, and maximum tone duration unchanged unless explicitly listed.

PresetPattern / frequenciesCycles & timingMorph / waveform
CustomUses form valuesUses form valuesUses form values
3:2 Hemiola (gentle)3:2; 440 / 554.37 HzT0 1.107 s; 6 cycles; 1.5× exponentialNone; Sine
4:3 Cross-rhythm4:3; 330 / 440 HzT0 0.687 s; 8 cycles; 2× exponentialNone; Sine
5:4 Quintuplet feel5:4; 392 / 523.25 HzT0 0.858 s; 8 cycles; 2× exponentialFrequency morph; Sine
7:4 Progressive rock7:4; 220 / 440 HzT0 1.340 s; 6 cycles; 1.8× exponentialNone; band-limited Square
5:3 Bell-like cross-rhythm5:3; 800 / 1200 HzT0 0.379 s; 10 cycles; 2.5× exponentialPan morph; Pluck; max tone 60 ms; attack 2 ms; decay 50 ms
8:5 Golden-ratio approximation8:5; 261.63 / 392 HzT0 1.207 s; 8 cycles; 1.618× exponentialFrequency morph; Sine
3:2:4 Triple layer3:2:4; 262 / 392 / 523.25 HzT0 0.460 s; 12 cycles; 2× exponentialRandom evolution; Sine; three real layers
Nancarrow Study 21 inspired17:18; 220 / 233.08 HzT0 3.577 s; 6 cycles; 1.06× exponentialNone; Pluck; max tone 80 ms
Reich-inspired phase drift12:12; 330 / 440 HzT0 2.740 s; 12 cycles; 1.02× linearNone; Sine; P2 phase offset moves 0 → 1 beat
Ligeti Etude feel5:7; 440 / 554.37 HzT0 0.527 s; 10 cycles; 2.2× exponentialRhythm morph; Sine; attack 3 ms; decay 40 ms
About the composer-named presets: “Nancarrow inspired,” “Reich inspired,” and “Ligeti Etude feel” are compositional references, not simulations or analytical reconstructions of specific works. The Nancarrow preset, for example, applies a mild shared acceleration to a 17:18 grid; it does not reproduce the opposing accelerando/ritardando of Study No. 21.

Morph types

ModeActual transformation from first to final cycle
NoneBeat counts, frequencies, amplitudes, and pan remain at their base values; only the acceleration law changes timing.
Frequency morphP1 frequency rises from 100% to 150% of its base value. P2 falls from 100% to 75%. If P3 exists, it falls to 90%. The paths may converge, cross, or remain separated depending on the starting frequencies.
Amplitude morphP1 moves from 100% to 50% of its base amplitude; P2 moves from 50% to 100%. This is a partial balance exchange, not a fade to silence.
Rhythm morphP1 gains up to four beats across the piece: base_beats + round(4 * progress). P2 and optional P3 keep their beat counts.
Pan morphP1 and P2 linearly exchange their starting pan positions. With the standard hidden positions, P1 moves from -0.5 to +0.5 and P2 from +0.5 to -0.5.
Random evolutionOnce per cycle: each active layer frequency is randomized to 80–120% of base, amplitude to 60–100%, and pan receives ±0.3 before clamping to -1…+1. Beat counts are unchanged.

Random seed

Random_seed = 0 initializes unpredictably. A positive seed makes the Random evolution event states reproducible. When Random evolution is not selected, synthesis is deterministic regardless of the seed field.

Tone & stereo synthesis

Each rhythmic event is rendered at the fixed internal sample rate of 44.1 kHz. Its duration is limited by both Max_tone_duration_ms and the current rhythmic density:

tone_duration = min(Max_tone_duration,
                    0.8 * smallest_IOI_in_current_cycle)

This prevents a tone from occupying more than 80% of the tightest layer spacing. If acceleration or a requested target duration would reduce an event below six samples, the script stops rather than rendering sub-sample-like clicks.

Envelope

Each event has a linear attack and a linear final decay. For very short events the requested times are automatically shortened: attack is at most one third of the tone duration and decay at most one half.

Waveforms

WaveformImplementation
SineSingle sinusoid at the event frequency.
Triangle (band-limited)Finite odd-harmonic approximation through the 9th partial, with alternating signs and 1/n² amplitudes. Partials above the Nyquist guard are omitted.
Square (band-limited)Finite odd-harmonic approximation through the 9th partial with 1/n amplitudes; out-of-range partials are omitted.
Pluck (decaying harmonics)Fundamental plus a decaying second harmonic (0.5·e-10t) and third harmonic (0.25·e-20t), subject to the Nyquist guard. It is a compact synthetic pluck-like spectrum, not a physical string model.

Fundamental frequencies must remain below 0.48 × 44100 = 21168 Hz. The same guard is checked again after frequency morphing or randomization.

Stereo placement

The output is always stereo. P1 starts at pan -0.5 and P2 at +0.5; the triple-layer preset places P1 at -0.65, P2 at +0.65, and P3 at center. The panning law is constant power:

angle = (pan + 1) / 2 * pi/2
left  = cos(angle)
right = sin(angle)

The Pan morph swaps P1 and P2 spatial positions over the piece. Random evolution adds cycle-level pan variation.

Parameters

ParameterDefaultMeaning
PresetCustomSelects one of the predefined configurations or leaves the form values active.
Base_duration_s2.0 sDuration of cycle 1 when Target total duration is 0.
Target_total_duration_s0If greater than 0, recalculates the initial cycle duration to meet this total duration under the chosen acceleration law.
Total_cycles8Number of shared rhythmic cycles; capped at 1000.
Pattern1_beats / Pattern2_beats3 / 4Number of evenly spaced events per cycle for each layer; each is capped at 1000.
Pattern1_frequency_Hz / Pattern2_frequency_Hz300 / 500 HzBase tone fundamentals before any morph.
Acceleration_factor2.0Final speed relative to cycle 1. >1 accelerates; 1 is steady; 0–1 decelerates.
Exponential_accelerationYesSelects a^p rather than linear interpolation from 1 to a.
Morph_typeNoneOptional cycle-level transformation in frequency, amplitude, rhythm, pan, or random parameters.
Max_tone_duration_ms100 msUpper limit for each event tone; current rhythmic spacing may shorten it further.
Attack_ms5 msRequested linear attack. Negative values are clamped to 0.
Decay_ms30 msRequested linear ending decay. Negative values are clamped to 0.
WaveformSineSine, finite band-limited triangle/square, or pluck-like decaying-harmonic tone.
Random_seed00 = unpredictable Random evolution; positive = reproducible. Negative values are clamped to 0.
Play_resultYesPlays the generated Sound after rendering.
Draw_visualizationYesDraws the actual generated event/timing/morph data.

Output behavior

Level consequence: because the final Sound is normalized to 0.9, absolute event amplitudes do not determine the final playback peak. They determine relative balance among events/layers before the global normalization.

Visualization

The v0.4 figure is driven by the same arrays used to render the audio, rather than by an independent illustrative approximation.

Turning the visualization off skips only drawing; it does not alter the precomputed event states or audio rendering.

Technical notes

Preset-specific processes

The Reich-inspired phase drift preset uses two equal 12-pulse grids. P2 receives a cycle-level offset that progresses from 0 to one complete P2 beat over the piece. Because one full beat is equivalent to the original periodic grid, the final cycle returns to an aligned onset set. This is a discrete, cycle-stepped phase process rather than continuous sample-by-sample phasing.

The 3:2:4 Triple layer preset genuinely renders P3 in addition to P1 and P2; its third layer has four beats per cycle, 523.25 Hz, amplitude 0.32, and center pan.

Event count and safety guards

The script precomputes all cycle states and event onsets before audio synthesis. It guards cycle count, beat counts, fundamental frequency, target timing, and minimum event duration. Panning is clamped to -1…+1 after morphing/randomization.

Further Reading