Routing Doctor
Analyzes all tracks in your REAPER project for routing problems. Identifies orphaned tracks, duplicate routing, skipped chain steps, and master leaks based on your configured signal flow.
Actions
| Action Name | Description |
|---|---|
NateWeiner: Routing Doctor - Check routing for errorsClick to copy | Analyzes routing and displays results in the console |
NateWeiner: Routing Doctor - Save routing analysis to diskClick to copy | Saves analysis to a text file |
How to Use
- Configure once — Tell it where your stems are (see Basic Setup below)
- Run the check action from the action list
- View results in the ReaScript console (Actions → Show ReaScript console)
Basic Setup
The core idea is simple: tell Routing Doctor where your instruments should end up. For most templates, that's a Stems folder. The script then checks that every track reaches one of those stems — and only one.
Creating Your Config File
- Open REAPER's scripts folder: Options → Show REAPER resource path, then navigate to
Scripts/NateWeiner/Project/Routing Doctor - Copy
RoutingConfig.template.luatoRoutingConfig.lua - Open
RoutingConfig.luain a text editor and modify it to match your template
Minimal Configuration
If you have a Stems folder that all your instruments should route to, here's all you need:
local RoutingConfig = {
targetChain = {
tracks(folder("Stems")), -- All tracks in your Stems folder
tracks(master()), -- Then to Master
},
}
return RoutingConfigThat's it. This tells Routing Doctor: "Every instrument should eventually reach something in the Stems folder." It doesn't matter how they get there — through folders, buses, or direct sends — as long as they arrive.
Adding Reverbs
If you have reverb or FX buses that instruments also send to, add them as parallel paths. This tells Routing Doctor that sending to both a stem AND a reverb is intentional:
local RoutingConfig = {
targetChain = {
tracks(folder("Stems")),
tracks(master()),
},
parallelPaths = {
tracks(folder("Reverbs")), -- Reverbs are OK to send to
},
}
return RoutingConfigIgnoring Non-Music Tracks
Some tracks aren't part of your music signal flow — video, dialogue, markers, etc. Exclude them so they don't get flagged:
local RoutingConfig = {
targetChain = {
tracks(folder("Stems")),
tracks(master()),
},
parallelPaths = {
tracks(folder("Reverbs")),
},
ignore = {
tracks({"Video", "Dialogue", "Click", "Markers"}),
},
-- Auto-ignore empty top-level tracks (marker tracks, etc.)
ignoreEmptyTopLevelTracks = true,
}
return RoutingConfigWhat It Catches
Here are the routing mistakes Routing Doctor will flag:
Orphaned Track
Problem: You add a new instrument but it's not routing to any stem — maybe it's going straight to Master or nowhere at all.
❌ ORPHANED (not routed to chain): 1 track(s)
• Track 47: "Harp"
Routing: → Master
⚠ Not routed to any chain target (expected: Stems)Fix: Route the track to the appropriate stem (or put it in a folder that does).
Duplicate Routing
Problem: A track is routing to multiple stems, which means it will be rendered twice.
❌ DUPLICATE ROUTING (multiple chain targets): 1 track(s)
• Track 12: "Brass" (folder)
Routing:
→ Brass Stem
→ Strings Stem
⚠ Routed to multiple chain entriesFix: Remove the extra send so it only goes to one stem.
Master Leak
Problem: A track routes to its stem correctly, but also has "Master/Parent Send" enabled — so it's going to Master twice (once through the stem, once direct).
❌ MASTER LEAK: 1 track(s)
• Track 38: "Percussion Stem"
Routing:
→ Full Mix ✓
→ Master (direct) ✗
⚠ Also routing to Master (disable parent send)Fix: Disable "Master/Parent Send" on the track.
Advanced: Multi-Layer Templates
If you have a more complex template with multiple routing layers (like section stems that feed into a full mix stem), you can define additional chain steps.
Example: Orchestral Template
Consider a template with sub-section stems (Low/High Brass, Short/Long Strings, etc.) that feed into section stems, which then feed a Full Mix:
📁 Woodwinds/
├── Flutes, Oboes, Clarinets, Bassoons
└── → Low Woodwinds Stem ─┬─► Woodwinds Stem ─┐
→ High Woodwinds Stem ─┘ │
│
📁 Brass/ │
├── Horns, Trumpets, Trombones, Tuba │
└── → Low Brass Stem ─┬─► Brass Stem ─────────┤
→ High Brass Stem ─┘ │
├─► Full Mix → Master
📁 Strings/ │
├── Violins, Violas, Cellos, Basses │
└── → Short Strings Stem ─┬─► Strings Stem ────┤
→ Long Strings Stem ─┘ │
│
📁 Percussion/ │
├── Timpani, Snare, Cymbals, etc. │
└── → Low Perc Stem ─┬─► Percussion Stem ─────┘
→ Mid Perc Stem ─┤
→ High Perc Stem ─┘
📁 Reverbs/ (parallel path - instruments can also send here)For this setup, you want to verify that:
- All instruments reach a sub-section stem (Low Brass, Short Strings, etc.)
- Sub-section stems reach their section stem (Brass Stem, Strings Stem, etc.)
- Section stems reach the Full Mix
- Full Mix reaches Master
Configuration
local RoutingConfig = {
targetChain = {
-- Step 1: Sub-section stems (where instruments should route)
tracks({
-- Woodwinds
"Low Woodwinds Stem", "High Woodwinds Stem",
-- Brass
"Low Brass Stem", "High Brass Stem",
-- Strings
"Short Strings Stem", "Long Strings Stem",
-- Percussion
"Low Perc Stem", "Mid Perc Stem", "High Perc Stem",
}),
-- Step 2: Section stems (sub-sections should route here)
tracks({
"Woodwinds Stem", "Brass Stem",
"Strings Stem", "Percussion Stem",
}),
-- Step 3: Full Mix
tracks("Full Mix"),
-- Step 4: Master
tracks(master()),
},
parallelPaths = {
tracks(folder("Reverbs")),
},
ignore = {
tracks({"Video", "Dialogue", "SFX", "Click"}),
},
ignoreEmptyTopLevelTracks = true,
}
return RoutingConfigWith multiple chain steps, Routing Doctor also catches skipped chain steps — like an instrument sending directly to Brass Stem instead of going through Low Brass Stem first, or a sub-section stem bypassing its section stem and going straight to Full Mix.
Configuration Reference
Helper Functions
tracks("Name")— Single track by exact nametracks({"A", "B", "C"})— Multiple tracks by nametracks(folder("Folder"))— All direct children of a foldertracks(folder("Folder", { matchPattern = "^Stem" }))— Only children matching a Lua patterntracks(folder("Folder", { excludePattern = "^%-$" }))— Exclude children matching a patterntracks(master())— The master track
Understanding the Output
The output shows:
- Number of tracks analyzed
- Any problems found, grouped by root cause
- For each problem: the track, its current routing, and why it's flagged
- Summary statistics
Example Output
=== Routing Doctor ===
Scanning 45 tracks...
Config: 2 chain step(s) defined
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PROBLEMS FOUND: 3
❌ ORPHANED (not routed to chain): 1 root cause(s), 2 affected track(s)
• Track 12: "Synth Lead"
Parent: 8:Synths [OFF]
Sends:
→ 15:Old FX Bus [MUTED]
⚠ All sends muted, parent send OFF
↳ + 1 child track(s) affected
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SUMMARY
Source tracks analyzed: 40
✓ Correctly routed: 37
⏭ Skipped: 5 (chain/parallel/ignored/utility)
❌ Problems: 3Requirements
- SWS Extension for REAPER
- REAPER 6.0+
How to Install
This script is distributed via ReaPack.
- Add the repository: Extensions → ReaPack → Import repositories... and paste:
https://nateweiner.com/dist/reaper/main/index.xmlClick to copy - Browse packages: Extensions → ReaPack → Browse packages
- Search for
Routing Doctor, right-click and install - Navigate to the Routing Doctor folder in your REAPER scripts directory
- Copy
RoutingConfig.template.luatoRoutingConfig.lua - Edit
RoutingConfig.luato match your template (see Configuration below)
See the full installation guide for more details.
How to Get Help
If you run into issues or have questions, check the REAPER forum for help and discussion.
Troubleshooting
Before posting, enable debug logging to gather diagnostic information:
- Install the Toggle Debug Logging package from ReaPack (search for
NateWeinerClick to copy) - Run the action:
NateWeiner: Toggle Debug Logging for Nate Weiner scriptsClick to copy - A dialog confirms debug logging is now ENABLED
- Open the ReaScript console: Actions → Show ReaScript console
- Run the script that's giving you trouble
- Copy the debug output from the console and include it in your forum post
Remember to disable debug logging when you're done (run the toggle action again) as it may slightly slow down script execution.