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 NameDescription
NateWeiner: Routing Doctor - Check routing for errorsAnalyzes routing and displays results in the console
NateWeiner: Routing Doctor - Save routing analysis to diskSaves analysis to a text file

How to Use

  1. Configure once — Tell it where your stems are (see Basic Setup below)
  2. Run the check action from the action list
  3. 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

  1. Open REAPER's scripts folder: Options → Show REAPER resource path, then navigate to Scripts/NateWeiner/Project/Routing Doctor
  2. Copy RoutingConfig.template.lua to RoutingConfig.lua
  3. Open RoutingConfig.lua in 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 RoutingConfig

That'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 RoutingConfig

Ignoring 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 RoutingConfig

What 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 entries

Fix: 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 RoutingConfig

With 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 name
  • tracks({"A", "B", "C"}) — Multiple tracks by name
  • tracks(folder("Folder")) — All direct children of a folder
  • tracks(folder("Folder", { matchPattern = "^Stem" })) — Only children matching a Lua pattern
  • tracks(folder("Folder", { excludePattern = "^%-$" })) — Exclude children matching a pattern
  • tracks(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: 3

Requirements

  • SWS Extension for REAPER
  • REAPER 6.0+

How to Install

This script is distributed via ReaPack.

  1. Add the repository: Extensions → ReaPack → Import repositories... and paste:
    https://nateweiner.com/dist/reaper/main/index.xml
  2. Browse packages: Extensions → ReaPack → Browse packages
  3. Search for Routing Doctor, right-click and install
  4. Navigate to the Routing Doctor folder in your REAPER scripts directory
  5. Copy RoutingConfig.template.lua to RoutingConfig.lua
  6. Edit RoutingConfig.lua to 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:

  1. Install the Toggle Debug Logging package from ReaPack (search for NateWeiner)
  2. Run the action: NateWeiner: Toggle Debug Logging for Nate Weiner scripts
  3. A dialog confirms debug logging is now ENABLED
  4. Open the ReaScript console: Actions → Show ReaScript console
  5. Run the script that's giving you trouble
  6. 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.

Other Scripts