Matrix Chain — User Guide
A four-slot AudioTools host for building compound Praat processing chains in series and parallel. Matrix Chain discovers compatible scripts, exposes their form parameters in one interface, renders the active chain through a single headless Praat process, and can optionally include compatible Python-bridge processors.
What this is
Matrix Chain is a host layer for Praat AudioTools. Instead of running one processing script, returning to the Objects window, selecting its result, and launching the next script manually, Matrix Chain can assemble up to four compatible processors into one reusable routing graph.
The host reads each script's form, recreates its parameters in a single Tk interface, and calls the original script with runScript. The individual AudioTools scripts remain the processors; Matrix Chain is the routing, parameter, compatibility, rendering, and preset layer around them.
Architecture
The launcher Matrix_Chain.praat verifies that exactly one Sound is selected, exports that Sound once as a 32-bit WAV file, writes a small manifest, and starts matrix_chain.py. The host scans the AudioTools library through praat_script_inspector.py, opens the Matrix interface, and waits for a render request.
When rendering, the Python host writes a temporary Praat wrapper containing the routing graph and the current parameter values. That wrapper reads the input once, calls the selected scripts, performs any requested branch mixing and global output processing, and writes one 32-bit result file. The original Praat process imports the result after the Matrix window is closed.
Quick start
- Select exactly one Sound in the Praat Objects window.
- Run
Matrix_Chain.praat. - In each row, choose a Category, a compatible Script, and a routing Mode.
- Click a slot row to edit that script's parameters in the lower panel.
- Use Series for sequential processing or consecutive Parallel rows for branches fed from the same stage input.
- Use Audition for a scratch render. Use Stop to cancel an active render or stop playback.
- When the chain is ready, click Apply → Praat.
- Close the Matrix window. The result is imported into Praat as a new Sound named from the source plus
_matrix_<duration>s.
Slots & routing
The host provides four rows. Each row has Category, Script, Mode, Branch %, and a status description. A row can be Off, Series, or Parallel.
| Mode | Signal behavior | Branch % |
|---|---|---|
| Off | The row is ignored. | Not used. |
| Series | The script receives the current chain Sound. Its output becomes the input to the next stage. | Not used. |
| Parallel | Consecutive Parallel rows receive copies of the same stage input. Their outputs are conformed as needed and summed into one new Sound. | Linear branch gain in the sum. It is not wet/dry. |
Series example
Parallel example
Only consecutive Parallel rows belong to the same branch group. A Series row ends the current parallel group and begins a new sequential stage.
Format conforming inside a parallel stage
Parallel branches can return different durations, sample rates, or channel counts. The host uses the longest branch duration and the highest branch sample rate as the target. Branches whose sample rate differs are resampled in Praat with precision 50.
Mono/stereo mismatches are conformed to stereo when stereo is the largest format. Mixed channel layouts that extend beyond stereo are treated conservatively; when channel counts differ and the largest layout exceeds stereo, the parallel target is folded to mono.
Script parameters
When you choose a script, the inspector parses its first Praat form block and the host builds matching widgets in the parameter panel. Numeric and text fields appear as entries, boolean fields as checkboxes, and choice/optionmenu fields as menus.
The host supports both legacy and modern Praat form syntax, including vector fields and multiline text fields. Menu values are passed back to runScript as option text, matching Praat's argument semantics.
| Control | Behavior |
|---|---|
| Reset to defaults | Restores the current script's parsed form defaults. |
| Force Play off | When the inspector identifies a playback boolean such as Play, Audition, Preview, Listen, or Play_result, the host sends it as off during chain rendering. |
| Force Draw off | For recognized boolean drawing/visualization controls, the host sends off during the render. |
Global controls
| Control | Default | Meaning |
|---|---|---|
| Dry/Wet % | 100% | Linear amplitude mix between the original input Sound and the complete processed chain. 100% is chain only; 0% is dry only. |
| Trim / fade / normalize | Off | Optional post stage: trims to the detected active region, applies edge fades, then peak-normalizes. |
| Safety ceiling | On | When the post stage is off, attenuates only if the output peak exceeds 0.99. If disabled, no host-level gain stage is applied. |
| Force Play off | On | Suppresses recognized script-level playback controls during chain rendering. |
| Force Draw off | On | Suppresses recognized boolean drawing/visualization controls during chain rendering. |
| Include Python bridges (slower) | Off | Rescans the py/ area and offers Python-backed Praat launchers that pass compatibility checks. |
| Timeout s | 300 s when launched from the Praat launcher | Maximum render time. Increase it for slow chains and especially for Python bridges. |
Post stage details
With Trim / fade / normalize enabled, the host analyses Intensity, uses a threshold 60 dB below the detected peak intensity to define the active region, applies a 20 ms half-cosine fade at each edge (capped at one quarter of the resulting duration), and scales the final peak to 0.98.
With the post stage off and Safety ceiling on, only peaks above 0.99 are attenuated. With both controls off, the chain output is left at its current level.
Compatibility inspector
praat_script_inspector.py statically scans the AudioTools library before scripts are offered in the Matrix. It reads form parameters, estimates the selected-Sound requirement, looks for audio-producing operations, checks common interactive blockers, and classifies Python bridges.
Typical eligible structure
- Requires one selected Sound, or is a no-input generator.
- Contains a recognizable audio-producing or Sound-readback operation.
- Can run without an editor/demo window or blocking interactive backend.
- Does not require two or more selected Sounds.
- Does not depend on a mandatory interactive file/folder chooser.
Examples of blockers
| Detected condition | Why it is blocked |
|---|---|
| Analysis/drawing only; no audio output | There is no Sound for the next slot. |
| Requires 2+ selected Sounds | A Matrix slot receives one current Sound, not an arbitrary Objects-window selection. |
| Input requirement unclear | The host cannot safely infer the script's selection contract. |
| Editor or demo window | Headless Praat cannot use an interactive editor as part of an unattended render. |
| Pause inside a loop/procedure | Would make the headless execution path interactive or ambiguous. |
| Mandatory chooser | A headless file/folder chooser cannot supply a user selection. |
| External corpus file-list dependency | The current Matrix catalog treats external corpus-folder requirements as non-portable. |
Runtime output contract
After every slot, the generated wrapper checks the selected Sound objects. A slot that leaves no Sound selected fails the render. If several Sounds are selected, the newest selected Sound is taken and the event is logged. A native script may modify its input Sound in place; a Python bridge is stricter and must produce a new Sound object.
Generators
A script classified as requiring no input is treated as a generator. Generator scripts are offered only in Slot 1 and are intended to be the first active stage in Series mode, because inserting a generator later would discard the signal built before it.
Python bridges
Python-backed AudioTools processors are opt-in. Enable Include Python bridges (slower) to rescan the py/ directory and expose compatible Praat launchers.
A bridge is considered chainable only when:
- the Praat side launches a Python backend;
- the backend is not detected as an interactive GUI/blocking program;
- after the external call, the Praat side reads audio back as a Sound object;
- the runtime slot actually produces a new Sound.
The inspector looks for common GUI frameworks and blocking calls including Tkinter, Qt/PySide, wx, Kivy, pygame, Streamlit, webview, Gradio, Dear PyGui, PySimpleGUI, mainloop(), input(), plt.show(), and GUI application execution. A backend that returns only an external file without reading it back into Praat is blocked. A bridge that reads its result as a LongSound is also blocked because the chain requires a Sound object.
PATH before launching headless Praat. This helps a bridge's internal python lookup resolve to the same environment that is already running Matrix Chain, reducing “works in the host but packages are missing in the bridge” failures.
Audio fidelity & file I/O
Matrix Chain is designed to avoid unnecessary intermediate quantization. The selected Praat Sound is exported to the host as a 32-bit integer PCM WAV. After the headless wrapper reads that file, native Praat slot outputs are passed in memory until the final result is saved once as another 32-bit WAV and returned to the original Praat session.
This removes the 16-bit input/output bottleneck that would otherwise quantize every Matrix render. The host can also read common PCM 8/16/24/32-bit and IEEE float WAV data for Audition, including WAVE_FORMAT_EXTENSIBLE headers.
Parallel routing can also introduce deliberate format conversion: branches with different sample rates are resampled to the highest branch rate before mixing. Global Dry/Wet may conform the original dry copy to the final processed format. These are functional routing operations, not hidden file-format conversions.
Level changes are separate from resolution
Safety ceiling and Trim / fade / normalize can change level by design. For a host-transparency A/B test, turn off the post stage and Safety ceiling, use 100% Dry/Wet, and choose processors that themselves make no normalization or sample-rate change.
Saving & restoring chains
Save chain… writes a JSON preset containing the four slot choices, routing modes, branch levels, current script parameters, global Dry/Wet, post setting, Safety ceiling state, and the Python-bridge inclusion state.
Load chain… restores that state. If a saved chain contains a Python bridge, Matrix Chain turns bridge scanning on and rescans before rebuilding the slots.
The host also stores the most recent chain and remembered Praat executable in matrix_chain_config.json next to matrix_chain.py. On the next launch, the previous chain is restored automatically when possible.
Installation & dependencies
| Component | Expected location / role |
|---|---|
Matrix_Chain.praat | Praat-side launcher. Select one Sound and run this script. |
py/matrix_chain.py | Python/Tk host, routing engine, wrapper generator, rendering and preset layer. |
py/praat_script_inspector.py | Static script scanner and compatibility classifier. |
py/matrix_chain_config.json | Created/updated by the host to remember the Praat executable and last chain. |
Required
- Praat, including an executable that the host can launch headlessly.
- Python 3 with Tkinter for the Matrix interface.
- The AudioTools library folder, because Matrix Chain scans and runs the original
.praatprocessors.
The launcher tries a configured Python first and then platform-appropriate Python commands. The host can auto-detect common Praat executable locations; the Praat… button lets you select the executable manually, and Test Praat checks that it can run headlessly and write audio.
Optional playback packages
sounddevice, soundfile, and numpy improve Audition support. Rendering itself does not depend on all three. On Windows the host can fall back to the standard winsound API by creating a temporary 16-bit playback copy; that copy is for Audition only and does not replace the 32-bit render.
Python-bridge dependencies
Each bridge can require its own Python packages. Enabling bridge scanning does not install those dependencies; it only makes compatible launchers available to the Matrix.
Limitations
- Four slots maximum. Matrix Chain is intentionally a compact host, not an unlimited modular patcher.
- One-Sound chain model. Effects that inherently require two or more simultaneously selected Sound objects are excluded.
- Static inspection has limits. The inspector recognizes common structures and blockers but cannot prove the full semantics of every arbitrary Praat script.
- Multi-selected outputs remain ambiguous. If a script leaves several Sounds selected, the host chooses the newest selected Sound and logs the condition.
- Interactive workflows are not chainable. Editors, demo windows, blocking GUI Python backends, and mandatory choosers are incompatible with unattended headless rendering.
- Corpus workflows are conservative. Scripts detected as needing external folder-based corpora are currently blocked rather than making unstated assumptions about external resources.
- Parallel multichannel routing is conservative. Mono/stereo is the primary supported use case; complex mismatched layouts can be folded to mono.
- Bridge performance varies. A Python-backed slot can dominate total render time and may need a larger timeout.
Troubleshooting
| Symptom | What to check |
|---|---|
| Praat NOT FOUND | Click Praat…, select the executable, then use Test Praat. The chosen path is remembered. |
| A script is missing from the list | Click Rescan and inspect Log. The script may have an eligibility blocker. Python-backed launchers also require Include Python bridges. |
| A generator is missing from Slot 2–4 | This is intentional. Generators ignore their input and are restricted to the first slot/first Series stage. |
| Argument-count mismatch | The form parser and the target script disagree about the number of fields. Rescan first; persistent cases indicate a form syntax the inspector does not yet parse correctly. |
| Slot left no Sound selected | The script did not satisfy the chain output contract. It cannot be used safely as a Matrix effect in its current form. |
| Python bridge produced no chainable Sound output | The bridge did not create a new Sound after its external backend returned. Check backend errors and its Praat-side readback step. |
| Render times out | Increase Timeout s, especially for Python, neural, corpus, or long-duration processors. |
| Audition renders but does not play | The render itself may be valid. Install an available playback path such as sounddevice, or check the platform fallback reported in the status/log. |
| Output is much quieter | Check Branch %, script-level dry/wet or normalization, global Dry/Wet, Safety ceiling, and the post stage. The log reports when the host Safety ceiling is applied. |
The Log window reports the catalog scan, blockers and warnings, render command, wrapper, stage progress, stdout/stderr, and the last stage reached when a render fails.
Further reading
- Boersma, P., & Weenink, D. Praat Manual — Scripting. Official documentation. Primary reference for the scripting model used by Matrix Chain.
- Boersma, P., & Weenink, D. Scripting 6.1: Arguments to the script. Official documentation. Documents
formfields,runScriptargument passing, booleans, choices and vectors. - Boersma, P., & Weenink, D. runScript. Official documentation. Reference for executing one Praat script from another with arguments.
- Boersma, P., & Weenink, D. Scripting 6.5: Calling system commands. Official documentation. Documents
runSubprocessand external-program calls used by Python bridges. - Boersma, P., & Weenink, D. Scripting 6.9: Calling from the command line. Official documentation. Documents headless
praat --runexecution and its limitations. - Python Software Foundation. tkinter — Python interface to Tcl/Tk. Official Python documentation. Reference for the GUI toolkit used by the Matrix host.