Spatial Panner — v1.0 User Guide
2D circular trajectory editor for multi‑channel spatialisation using DBAP (Distance‑Based Amplitude Panning). Draw a moving source path inside a circle, assign time stamps, and render to N‑channel audio (default 8 speakers in a ring).
What this does
Spatial Panner lets you draw a moving sound source trajectory on a 2D circular stage. The source position at each moment is converted to gains for an arbitrary number of loudspeakers using Distance‑Based Amplitude Panning (DBAP). The result is a multi‑channel audio file (e.g., 8‑channel WAV) that you can play back on a multichannel system or further process in Praat.
- Draw trajectories by left‑clicking in the circle – points are added with automatically assigned times.
- Drag points to reposition; right‑click to delete (start/end anchors are protected).
- Double‑click a point to manually edit its time (in seconds).
- Switch speaker layouts on the fly: 4, 6, or 8 speakers equally spaced around the ring.
- Real‑time preview of trajectory points in a side panel and on a time ruler below the stage.
- DBAP with RMS normalisation ensures equal perceived loudness regardless of position.
Quick start
- In Praat, select exactly one Sound object (mono or stereo). Stereo will be downmixed to mono for spatial rendering.
- Run script… →
Spatial_Panner.praat. - The Python GUI opens with a circular stage. Two anchor points already exist: at the centre at time 0 and at the centre at the sound’s duration.
- To add a trajectory point: left‑click anywhere inside the circle. The point is given a time halfway between the previous point and the end anchor.
- To move a point: left‑click and drag. Points are constrained to the circle.
- To delete a point: right‑click on it (anchors cannot be deleted).
- To edit a point’s time: double‑click it and enter a new time within the allowed range.
- You can change the number of speakers using the buttons in the right panel (4, 6, 8). The speaker layout is displayed in the listbox.
- When satisfied, click Apply. The engine computes DBAP gains, renders an N‑channel WAV, and imports it back into Praat as
originalname_spatial.
numpy, soundfile, scipy. Tkinter is included with Python.
The output is a multichannel WAV (32‑bit float). Praat can read up to 250 channels, but for playback you will need a multichannel audio interface or a player that can downmix.
GUI & trajectory editing
Interface preview (dark theme)
┌──────────────────────────────────────────────────────┐
│ sound.wav 3.45s 44100Hz mono → 8-ch output L-click: add/drag R-click: delete Double-click: edit time │
├───────────────────────┬──────────────────────────────┤
│ ┌───────────┐ │ Speaker Layout │
│ / \ │ [4 spk] [6 spk] [8 spk] │
│ │ ● │ │ │
│ │ ● ● │ │ Sp1 0.0° r=1.00 │
│ \ / │ Sp2 45.0° r=1.00 │
│ └───────────┘ │ Sp3 90.0° r=1.00 │
│ ⚓0.00s •0.85s │ Sp4 135.0° r=1.00 │
│ ⚓3.45s │ ... │
├───────────────────────┴──────────────────────────────┤
│ ══╤══╤══╤══╤══╤══╤══╤══╤══ ⚫ ⚫ │
│ 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 s │
├──────────────────────────────────────────────────────┤
│ Ready. │
├──────────────────────────────────────────────────────┤
│ [ Reset ] [ Cancel ] [ ▶ Apply ] │
└──────────────────────────────────────────────────────┘
Stage elements
- Circle – represents the listening stage. Coordinates are normalised to -1…+1 in both axes. The centre is (0,0).
- Speaker markers – magenta circles with labels (Sp1, Sp2, …). Default layout: 8 speakers equally spaced around the ring, starting at top (0°) and going clockwise.
- Cyan line with arrow – the trajectory path. Arrow shows direction of motion.
- Yellow points – anchor points (start and end). Their time is fixed (0 and duration), but they can be moved in space.
- Cyan points – intermediate trajectory points. They can be moved in space and time.
- Time ruler – horizontal bar showing point positions as vertical lines (yellow for anchors, cyan for interior points).
- Right panel – lists speaker coordinates and all trajectory points with their times and (x,y) positions.
Editing operations
| Action | Result |
|---|---|
| Left‑click empty area | Add a new trajectory point at that position. Time is automatically assigned halfway between previous point and end anchor. |
| Left‑click + drag point | Move the point (constrained to circle). |
| Right‑click point | Delete point (anchors cannot be deleted). |
| Double‑click point | Open dialog to manually edit time (range enforced by neighbours). |
| Click speaker buttons | Switch to 4, 6, or 8 equally spaced speakers. |
Speaker layouts
The default speaker arrangement is 8 speakers equally spaced around a circle of radius 1.0, starting at top (0°) and going clockwise. You can switch between 4, 6, and 8 speakers using the buttons in the right panel.
| Number | Angles (degrees, clockwise from top) |
|---|---|
| 4 | 0°, 90°, 180°, 270° |
| 6 | 0°, 60°, 120°, 180°, 240°, 300° |
| 8 | 0°, 45°, 90°, 135°, 180°, 225°, 270°, 315° |
The speaker positions are fixed to the edge of the circle (radius 1.0). DBAP gains are computed based on Euclidean distance from the source position to each speaker.
Custom layouts: To use a different speaker arrangement, edit the make_ring_speakers call in the Python script. You can change the radius, add an offset, or define completely arbitrary positions by modifying the DEFAULT_SPEAKERS list.
DBAP (Distance‑Based Amplitude Panning)
For source at position (sx, sy) and speaker i at (spk_x, spk_y):
d_i = distance(s, spk_i) + εraw_i = 1 / (d_i^k)gain_i = raw_i / √(∑ raw_j²)Parameters:
k (rolloff exponent) = 1.0 (default)
ε (minimum distance) = 0.02
Normalisation:
√(∑ gain_i²) = 1 (RMS‑preserving)
DBAP has several advantages over traditional VBAP:
- Works with any speaker arrangement, not just regular polygons.
- Creates smooth transitions even when the source passes near a speaker.
- The ε parameter prevents division‑by‑zero and ensures energy is smoothly concentrated when the source is exactly at a speaker position.
- RMS normalisation guarantees that a source moving anywhere on the stage maintains constant perceived loudness (assuming speakers are perfectly matched).
The current implementation uses vectorised numpy operations for speed, computing gains for all samples at once. The trajectory is linearly interpolated between breakpoints.
FAQ / troubleshooting
Install: pip install numpy scipy soundfile. On Windows, the script uses py (Python launcher).
Check the Info window in Praat – the Python engine prints detailed debug info. Look for “Output shape” and “Gains shape”. If the number of channels doesn’t match your expected speaker count, verify that the speaker layout was set correctly.
That’s intentional – the stage is the unit circle. Points cannot go outside because they represent positions inside the listening area. If you need positions outside (e.g., for extra‑loudspeaker effects), you would need to modify the stage radius and speaker positions in the script.
This ensures the trajectory remains monotonic in time (no backwards jumps). If you need a point to come before a previous point, you must delete and re‑add in the correct order.
If processing fails, a debug file (output_spatial_debug.txt) is saved alongside the output WAV. It contains the trajectory, gain statistics, and any error tracebacks.
Praat can play multichannel sounds, but it will downmix to stereo on most systems. To hear the full spatial effect, you need a multichannel audio interface and a player like Ardour, Reaper, or a custom Python script with soundfile + pyaudio.
Modifying the speaker layout
To change the default speaker arrangement, edit the line:
DEFAULT_SPEAKERS = make_ring_speakers(8, radius=1.0, offset_deg=0.0)
You can also define an explicit list, e.g.:
DEFAULT_SPEAKERS = [
("L", 90.0, 1.0),
("R", 270.0, 1.0),
("C", 0.0, 0.5),
]
Angles are in degrees, 0° = top, increasing clockwise. Radius can be less than 1.0 for speakers inside the circle.