Arranger — User Guide

A visual multi-clip arrangement and stereo-mixing bridge for Praat AudioTools: selected Sounds are exported to a Python/Tkinter timeline where they can be repositioned, balanced, faded, auditioned, and rendered back into Praat as a new stereo Sound.

Author: Shai Cohen Version: 1.5 (2026) License: MIT License Praat front end: Arranger.praat Python GUI/renderer: arranger.py Repo: GitHub
Contents:

What this does

Arranger turns a set of selected Praat Sound objects into movable clips on a visual timeline. Each selected Sound becomes one clip. You can change its start time, lane, gain, stereo balance, fade-in, and fade-out, then render the complete arrangement into a stereo WAV that is automatically imported back into Praat.

Selected Praat Sounds → unify sample rates → temporary WAV clips → JSON manifest → Python/Tkinter arranger → stereo mix → temporary result WAV → new Praat Sound
Arranger is a non-destructive bridge. The selected Praat Sounds are never moved, resampled, faded, or gain-adjusted in place. All arrangement decisions are applied to exported working copies and the newly rendered result.

Praat ↔ Python workflow

Praat front end

Arranger.praat:

  1. collects the selected Sounds and their metadata;
  2. finds the highest sample rate in the selection;
  3. resamples temporary copies when necessary;
  4. exports one temporary WAV per clip;
  5. writes a JSON manifest containing clip names, durations, channels, sample rate, default lane, and default start time;
  6. launches the Python GUI synchronously;
  7. imports the rendered stereo WAV when Render completes;
  8. removes the temporary files.

Python GUI / renderer

arranger.py:

The GUI is modal from Praat's point of view: Praat waits while the Python process is open. Closing with Cancel returns no mix and the Praat script cleans up.

Requirements

Required

The Praat front end explicitly tests whether Python can import tkinter before launching the arranger.

Optional

PackageRoleIf missing
numpyFast vectorized mixing and PCM decode/write path.Final Render still works through the pure-Python standard-library fallback.
sounddeviceNon-blocking Audition playback.Audition is unavailable; final Render still works.

For Audition:

pip install numpy sounddevice

Python discovery

The Praat front end uses python on Windows and python3 on Linux/Unix. On macOS it first checks several common Homebrew/framework paths before falling back to python3.

The Python arranger is searched in this order:

preferencesDirectory$/plugin_AudioTools/py/arranger.py then: arranger.py beside the running Praat script

Quick start

  1. Select one or more Sound objects in Praat.
  2. Run Arranger.praat.
  3. The Python Arranger window opens with one clip per selected Sound.
  4. Drag clips horizontally to change their start times.
  5. Drag vertically to another lane if that helps organize the layout.
  6. Drag the yellow handles to set fade-in and fade-out.
  7. Right-click a clip to edit gain and pan.
  8. Use Audition to preview when numpy and sounddevice are available.
  9. Click Render to create the stereo result and return it to Praat.
Cancel discards the current arrangement. There is no separate project/session file: the GUI state exists only for the current run.

Timeline & lanes

Initial layout

Every selected Sound starts at:

start time = 0.0 s

The first selected Sound is placed on lane 1, the second on lane 2, and so on. The number of lanes equals the number of selected clips.

A lane is only a visual organizational row. It is not an audio bus, channel, output track, or isolation layer. Clips from every lane are summed into the same final stereo mix.

Initial project span

The manifest's initial project_duration is the sum of all selected source durations. This value establishes a generous initial GUI timeline width; it is not the duration of the default arrangement, because all default clips begin at time 0.

Dynamic extension

If a clip is moved beyond the initial span, the timeline expands automatically to include its new end time.

Zoom

SettingValue
Default zoom80 pixels/second
Minimum10 pixels/second
Maximum400 pixels/second

Horizontal and vertical scrollbars allow long timelines and large clip selections to remain usable.

Moving clips

Left-drag a clip body to move it:

Start time is clamped at 0 seconds. Negative placement is not supported.

The clip duration itself does not change when it is moved. Arranger has no trim, cut, time-stretch, slip-edit, or source-offset control in v1.5.

Reset All

Reset All restores every clip to the original manifest state:

start = 0.0 s lane = original selection lane gain = 0.0 dB pan = center fade-in = 0 fade-out = 0

Gain & pan

Right-click a clip to open its gain/pan popup. On platforms where standard right-click differs, middle-click or Ctrl-click is also bound to the same action.

Gain

RangeStepDSP law
−24 to +24 dB0.5 dBgainLinear = 10^(gainDB / 20)

Pan is stereo balance

In v1.5, pan is deliberately a balance control, not an equal-power mono panner:

pan = 0: left gain = 1 right gain = 1 pan < 0: left = 1 right = cos((-pan) × π/2) pan > 0: left = cos(pan × π/2) right = 1

Therefore a stereo clip at center and 0 dB gain remains at unity on both channels. It is not attenuated by −3 dB at center.

Pan valueResult
−1Left retained, right reduced to zero.
0Both channels retained at unity.
+1Right retained, left reduced to zero.

The GUI changes pan in 0.05 steps.

Fade handles

Each clip has a yellow handle at its left and right edge. Dragging these handles changes fade duration without trimming the clip.

Fade-in

The amplitude envelope rises linearly from exactly 0 to exactly 1 across the requested fade samples.

Fade-out

The amplitude envelope falls linearly from exactly 1 to exactly 0 across the requested fade samples.

fade-in: 0 → 1 fade-out: 1 → 0 clip envelope: fadeInEnvelope × fadeOutEnvelope

The GUI prevents the two fade handles from consuming the entire clip: each fade is limited so that at least about 10 ms remains outside the combined requested fades.

These are per-clip edge fades. They are not automatic crossfades between adjacent or overlapping clips. If two faded clips overlap on the timeline, their already-faded signals are simply summed.

Audition & Stop

Audition calls the same internal _compute_mix() routine used by final Render. It therefore previews the same placement, gain, pan, fades, overlap summation, duration, and peak-safety rule as the final mix.

Audition requires both numpy and sounddevice. Playback is non-blocking, so the GUI remains interactive.

Stop calls sounddevice.stop().

Missing Audition dependencies do not prevent final rendering. The status bar reports the missing package instead of terminating Arranger.

Render path

When Render is clicked, Arranger:

  1. stops any active Audition;
  2. computes the complete stereo mix;
  3. writes the result as 16-bit stereo PCM WAV;
  4. writes a completion JSON containing result path, duration, channel count and clip count;
  5. closes the GUI;
  6. returns control to Praat.

Praat reads the WAV into a new Sound and then deletes the temporary WAV, manifest, clip exports, completion JSON, and error file.

Arranger does not save a reusable arrangement manifest after Render. The temporary manifest contains only the initial clip defaults; GUI edits are rendered directly into audio.

Sample rate & channel handling

Unified project sample rate

Praat determines:

targetSampleRate = maximum sample rate across all selected Sounds

Any selected Sound at a lower sample rate is copied and resampled to that rate with Praat precision 50 before export. The user's original objects remain untouched.

Mono

A mono clip is duplicated internally:

L = mono R = mono

Pan then behaves as a normal left/right balance on those duplicate channels.

Stereo

Channels 1 and 2 are used as L and R. At 0 dB / center / no fades, they enter the mix without the previous center-pan attenuation.

More than two channels

For a 3+ channel source, Arranger reads the file with the correct multichannel frame stride but uses only channels 1 and 2 for the stereo mix. Channels 3 and above are not mixed into the output.

Supported PCM input widths in the Python renderer

The decoder handles 8-, 16-, 24-, and 32-bit integer PCM WAV data. Praat's temporary exports are normally the standard WAV format produced by Save as WAV file.

Output format

The renderer always writes:

2 channels 16-bit PCM project target sample rate

Mixing & peak safety

All clips are summed sample-by-sample into the same stereo buses. Lane position has no effect on mixing.

mixL += clipL × gain × panL × fadeEnvelope mixR += clipR × gain × panR × fadeEnvelope

Overlap

Timeline overlap is ordinary additive mixing. Arranger does not automatically duck, crossfade, compress, or normalize overlapping clips.

Final peak safety

After all clips have been summed, the renderer checks the largest absolute sample across both channels:

peak = max(abs(left samples), abs(right samples)) if peak > 1.0: scale = 0.98 / peak L *= scale R *= scale else: leave mix unchanged

This is an attenuate-only safety stage, not target normalization. A mix whose peak is 0.60 stays at 0.60; a mix whose peak is 1.20 is attenuated so its new peak is 0.98.

The test is based on ordinary sample peaks in the floating-point mix. It is not true-peak or intersample-peak limiting.

Output duration

The renderer allocates a buffer long enough for the latest placed clip, plus temporary safety headroom. The delivered audio is then trimmed to the last sample actually written by any clip.

renderedDuration ≈ max(clip.start + decodedClipDuration)

The placement extent is preserved even if a clip ends in digital silence or its fade reaches zero at the end.

The output duration is not the sum of source durations. If all clips start at 0, the result is approximately as long as the longest clip. If clips are moved later, the result extends to the latest clip end. Overlap does not shorten a clip.

Praat output

After the rendered WAV is imported, Praat names the Sound from the number of clips and the actual rendered duration:

arrangement_<N>clips_<duration rounded to 0.1 s>s

Examples:

arrangement_3clips_8.4s
arrangement_7clips_21.0s

The output is selected and automatically played at the end of the Praat script.

The Info window reports:

Limits & important distinctions

No trimming or source-offset editing

A clip always represents its complete exported Sound. v1.5 provides placement, gain, pan and fades, but no source-in/source-out trim handles.

No time stretching or pitch shifting

Moving a clip changes only its timeline position. Its playback rate and duration are unchanged.

No track processing

Lanes have no independent mute, solo, gain, pan, effects, bus routing, or output assignment.

No project save / reopen

Reset can restore the defaults during the active session, but GUI edits are not serialized as a persistent arrangement project.

Maximum two source channels per clip

Multichannel WAV decoding is safe, but only channels 1 and 2 are used in the stereo renderer.

Audition is optional; Render is not

sounddevice and numpy are needed for Audition. NumPy is only an optimization for final Render; a standard-library mixer remains available.

Gain can create clipping before final safety scaling

Positive per-clip gain and overlapping clips can raise the floating mix above ±1. Arranger does not distort or hard-clip that floating buffer; it applies the final global attenuation when the peak exceeds 1.0, then quantizes the safe mix to 16-bit PCM.

Errors return to Praat

The Python process writes a traceback to the temporary error file on failure. Praat prints that traceback in the Info window before stopping, rather than treating a crash as a normal Cancel.