Skip to content

🐛 Debug Configurations - AudioLab

Debugger launch configurations for AudioLab audio plugin development


📋 Table of Contents

  1. Overview
  2. Files in This Directory
  3. Available Configurations
  4. Debug Workflow
  5. DAW Integration
  6. Configuration Details
  7. Keyboard Shortcuts
  8. Platform-Specific Debugging
  9. Advanced Debugging
  10. Troubleshooting

Overview

Purpose: Debug AudioLab plugins in DAWs, standalone apps, and unit tests.

What are Launch Configurations? - Debugger setups for different scenarios - Specify executable, arguments, environment - Breakpoint support, variable inspection - Step-through debugging (F10, F11) - Watch expressions, call stack analysis

Use Cases: - Debug plugin loaded in Reaper/Logic/Ableton - Debug standalone application - Debug unit tests (Catch2) - Attach to running DAW process - Analyze crash dumps (core dumps)


Files in This Directory

launch.json

Primary debug configurations for AudioLab.

Content: - Plugin debugging: Reaper, Logic Pro, Ableton Live - Standalone debugging: Debug standalone app - Test debugging: Debug unit tests - Attach configurations: Attach to running process - Core dump analysis: Post-mortem debugging

Location: vscode/launch/launch.json

Used by: - Debug panel (Ctrl+Shift+D) - F5 key (start debugging) - Run and Debug view


Available Configurations

Select configuration from Debug panel dropdown (Ctrl+Shift+D).

Plugin Debugging

Configuration Platform Description
Debug Plugin (Reaper) Windows/Linux Launch Reaper with plugin loaded
Debug Plugin (Reaper macOS) macOS Launch Reaper with plugin (macOS)
Debug Plugin (Logic Pro) macOS Launch Logic Pro with plugin
Debug Plugin (Ableton Live) All Launch Ableton Live with plugin
Debug Plugin (Standalone) All Debug standalone application

Test Debugging

Configuration Platform Description
Debug Unit Tests All Debug Catch2 test executable
Debug Audio Tests All Debug audio processing tests
Debug DSP Tests All Debug DSP algorithm tests
Debug Single Test All Debug specific test case

Advanced Debugging

Configuration Platform Description
Attach to Process All Attach to running DAW/app
Attach to Reaper All Quick attach to Reaper process
Debug Core Dump Linux Analyze crash dump file
Remote Debug (SSH) Linux Debug on remote machine

Debug Workflow

Basic Workflow

1. Set Breakpoints

Method 1: Click left gutter (next to line number)
Method 2: Press F9 on line
Method 3: Right-click → Insert Breakpoint

Red dot appears = Breakpoint set
Hollow red circle = Breakpoint disabled

2. Select Debug Configuration

1. Open Debug panel: Ctrl+Shift+D (Cmd+Shift+D on macOS)
2. Select config from dropdown (top of panel)
   Example: "Debug Plugin (Reaper)"
3. Config defines:
   - Which executable to run (Reaper.exe)
   - Arguments to pass
   - Working directory

3. Start Debugging

Method 1: Press F5
Method 2: Click green play button (Debug panel)
Method 3: Menu: Run → Start Debugging

What happens:
- DAW launches (or app starts)
- Debugger attaches
- Execution pauses at breakpoints

4. Use Debug Controls

F5         - Continue (run until next breakpoint)
F10        - Step Over (execute line, don't enter functions)
F11        - Step Into (enter function calls)
Shift+F11  - Step Out (exit current function)
Shift+F5   - Stop debugging
Ctrl+Shift+F5 - Restart debugging

5. Inspect Variables

VARIABLES panel (left sidebar):
- Local variables
- Function arguments
- Global variables

Hover over variable in code:
- Shows current value
- Can expand objects/arrays

WATCH panel:
- Add custom expressions
- Example: "buffer.getNumSamples()"

6. View Call Stack

CALL STACK panel:
- Shows function call hierarchy
- Click frame to jump to that function
- Useful for understanding execution flow

Example:
  processBlock() <-- Current
  AudioProcessor::process()
  VST3Wrapper::process()
  ReaperHost::runAudio()

DAW Integration

Debugging in Reaper

Windows Configuration:

{
  "name": "Debug Plugin (Reaper)",
  "type": "cppdbg",
  "request": "launch",
  "program": "C:/Program Files/REAPER (x64)/reaper.exe",
  "args": [],
  "cwd": "${workspaceFolder}",
  "environment": [],
  "externalConsole": false,
  "MIMode": "gdb",
  "setupCommands": [
    {
      "description": "Enable pretty-printing for gdb",
      "text": "-enable-pretty-printing",
      "ignoreFailures": true
    }
  ],
  "preLaunchTask": "Build: Debug"
}

Workflow: 1. Build plugin: preLaunchTask runs "Build: Debug" 2. Plugin copied to Reaper VST3 folder (CMake post-build) 3. Reaper launches 4. Load plugin in Reaper track 5. Breakpoint hits when plugin processes audio

Tips: - Create Reaper test project: test_projects/debug.rpp - Pre-load plugin in project for faster workflow - Use -audiocfg 0 to prevent audio device dialog


Debugging in Logic Pro (macOS)

macOS Configuration:

{
  "name": "Debug Plugin (Logic Pro)",
  "type": "lldb",
  "request": "launch",
  "program": "/Applications/Logic Pro X.app/Contents/MacOS/Logic Pro X",
  "args": [],
  "cwd": "${workspaceFolder}",
  "preLaunchTask": "Build: Debug"
}

Workflow: 1. Build plugin (Universal Binary: x86_64 + arm64) 2. Plugin copied to ~/Library/Audio/Plug-Ins/VST3/ 3. Logic launches 4. Create new track → Insert plugin 5. Breakpoint hits

Tips: - Logic uses component validation: First load is slow - Create template project with plugin pre-loaded - Use Console.app to see plugin logs


Debugging in Ableton Live

Configuration:

{
  "name": "Debug Plugin (Ableton Live)",
  "type": "cppdbg",
  "request": "launch",
  "program": "C:/ProgramData/Ableton/Live 11 Suite/Program/Ableton Live 11 Suite.exe",
  "args": [],
  "cwd": "${workspaceFolder}",
  "preLaunchTask": "Build: Debug"
}

macOS:

"program": "/Applications/Ableton Live 11 Suite.app/Contents/MacOS/Ableton Live 11 Suite"

Workflow: 1. Build and copy plugin 2. Ableton launches 3. Create MIDI/Audio track 4. Drag plugin from browser 5. Debug as audio plays


Configuration Details

Anatomy of a Launch Configuration

{
  "name": "Config Name",              // Display name in dropdown
  "type": "cppdbg",                   // Debugger type (cppdbg, lldb)
  "request": "launch",                // launch or attach
  "program": "/path/to/exe",          // Executable to run/attach
  "args": ["--flag", "value"],        // Command-line arguments
  "cwd": "${workspaceFolder}",        // Working directory
  "environment": [                    // Environment variables
    {
      "name": "MY_VAR",
      "value": "my_value"
    }
  ],
  "preLaunchTask": "Build: Debug",    // Task to run before launch
  "postDebugTask": "Clean Up",        // Task after debug session
  "stopAtEntry": false,               // Pause at main() entry
  "externalConsole": false,           // Use external console window
  "MIMode": "gdb",                    // Debugger: gdb, lldb
  "setupCommands": [                  // Debugger init commands
    {
      "text": "-enable-pretty-printing"
    }
  ]
}

Request Types

1. Launch (request: "launch")

  • Purpose: Start new process
  • Use Case: Launch DAW, standalone app, test executable
  • Example: Launch Reaper with plugin

2. Attach (request: "attach")

  • Purpose: Attach to running process
  • Use Case: DAW already running, attach debugger
  • Example: Attach to existing Reaper.exe

Attach Configuration:

{
  "name": "Attach to Process",
  "type": "cppdbg",
  "request": "attach",
  "processId": "${command:pickProcess}",  // Prompts to select process
  "MIMode": "gdb"
}

Workflow: 1. Start DAW manually 2. Load plugin 3. Run "Attach to Process" config 4. Select DAW process from list 5. Debugger attaches, breakpoints active


Debugger Types

Windows: - cppdbg (Microsoft C++ debugger via GDB/LLDB) - cppvsdbg (Visual Studio debugger, requires C/C++ extension)

macOS: - lldb (LLDB debugger from Xcode) - cppdbg (also works on macOS)

Linux: - cppdbg (GDB debugger)

Choice: - cppdbg: Cross-platform, works on all OS - cppvsdbg: Windows-only, better integration with MSVC - lldb: macOS-specific, best for macOS development


Keyboard Shortcuts

Debug workflow shortcuts (see keybindings/README.md):

Windows/Linux

F5                - Start debugging / Continue
Shift+F5          - Stop debugging
Ctrl+Shift+F5     - Restart debugging
Ctrl+F5           - Run without debugging

F9                - Toggle breakpoint
F10               - Step over
F11               - Step into
Shift+F11         - Step out

Ctrl+Shift+D      - Open Debug panel

macOS

F5                - Start debugging / Continue
Shift+F5          - Stop debugging
Cmd+Shift+F5      - Restart debugging
Cmd+F5            - Run without debugging

F9                - Toggle breakpoint
F10               - Step over
F11               - Step into
Shift+F11         - Step out

Cmd+Shift+D       - Open Debug panel

Platform-Specific Debugging

Windows (MSVC)

Debugger: cppvsdbg (recommended) or cppdbg

Configuration:

{
  "name": "Debug Plugin (Windows MSVC)",
  "type": "cppvsdbg",
  "request": "launch",
  "program": "C:/Program Files/REAPER (x64)/reaper.exe",
  "args": [],
  "cwd": "${workspaceFolder}",
  "symbolSearchPath": "${workspaceFolder}/build/Debug",
  "externalConsole": false,
  "logging": {
    "moduleLoad": false,
    "trace": false
  }
}

Features: - Native Windows debugging - Better symbol resolution - Faster than GDB on Windows - Edit and Continue (some cases)

Requirements: - C/C++ Extension Pack installed - MSVC compiler (cl.exe) - .pdb debug symbols


macOS (LLDB)

Debugger: lldb

Configuration:

{
  "name": "Debug Plugin (macOS)",
  "type": "lldb",
  "request": "launch",
  "program": "/Applications/Reaper.app/Contents/MacOS/REAPER",
  "args": [],
  "cwd": "${workspaceFolder}",
  "preLaunchTask": "Build: Debug"
}

Features: - Native macOS debugging - dSYM symbol support - Objective-C++ support - Apple Silicon (arm64) support

Tips: - Generate dSYM: -g -gdwarf-2 in CMake - Code signing: Debug builds auto-signed - Sandbox: May need entitlements for DAW debugging


Linux (GDB)

Debugger: cppdbg (uses GDB)

Configuration:

{
  "name": "Debug Plugin (Linux)",
  "type": "cppdbg",
  "request": "launch",
  "program": "/usr/bin/reaper",
  "args": [],
  "cwd": "${workspaceFolder}",
  "MIMode": "gdb",
  "setupCommands": [
    {
      "description": "Enable pretty-printing",
      "text": "-enable-pretty-printing",
      "ignoreFailures": true
    }
  ],
  "preLaunchTask": "Build: Debug"
}

Tips: - Install GDB: sudo apt install gdb - Disable ASLR: setarch $(uname -m) -R gdb - Core dumps: ulimit -c unlimited


Advanced Debugging

Conditional Breakpoints

Set condition on breakpoint:

1. Set breakpoint (F9)
2. Right-click red dot → Edit Breakpoint
3. Enter condition:
   Examples:
   - sampleIndex == 1024
   - buffer.getNumSamples() > 0
   - parameterValue < 0.0f
4. Breakpoint only hits when condition true

Use Case: Debug specific audio buffer frame without stopping on every call.


Logpoints (Non-Breaking Breakpoints)

Print message without stopping:

1. Right-click line → Add Logpoint
2. Enter message: "Sample value: {sampleValue}"
3. Logpoint prints to Debug Console
4. Execution continues (no pause)

Example:

// Logpoint at line 42:
// Message: "Processing buffer: {buffer.getNumSamples()} samples"

void processBlock(AudioBuffer<float>& buffer)
{
    // Logpoint here prints: "Processing buffer: 512 samples"
    for (int i = 0; i < buffer.getNumSamples(); ++i)
    {
        // ...
    }
}


Watch Expressions

Monitor custom expressions:

1. Open WATCH panel (Debug sidebar)
2. Click + to add expression
3. Enter expression:
   Examples:
   - buffer.getWritePointer(0)[0]
   - std::sqrt(paramValue * 2.0f)
   - myVector.size()
4. Expression updates as you step through code

Use Case: Monitor complex calculations, vector sizes, buffer contents.


Call Stack Analysis

Understand execution flow:

CALL STACK panel shows:
  processBlock() at AudioProcessor.cpp:142  <-- Current frame
  process() at VST3Wrapper.cpp:89
  runAudio() at ReaperHost.cpp:234
  audioThread() at AudioEngine.cpp:56

Actions:
- Click frame to view code at that level
- Inspect variables at each frame
- Understand how you got to current line

Memory Debugging (Valgrind - Linux)

Detect memory leaks:

{
  "name": "Debug with Valgrind",
  "type": "cppdbg",
  "request": "launch",
  "program": "/usr/bin/valgrind",
  "args": [
    "--leak-check=full",
    "--track-origins=yes",
    "${workspaceFolder}/build/Debug/AudioLab_Tests"
  ],
  "cwd": "${workspaceFolder}",
  "MIMode": "gdb"
}

Output:

==12345== LEAK SUMMARY:
==12345==    definitely lost: 512 bytes in 1 blocks
==12345==    indirectly lost: 0 bytes in 0 blocks

Use Case: Find memory leaks before plugin release.


Core Dump Analysis (Linux)

Debug crash after it happens:

1. Enable core dumps:

ulimit -c unlimited

2. Reproduce crash (generates core file)

3. Debug configuration:

{
  "name": "Debug Core Dump",
  "type": "cppdbg",
  "request": "launch",
  "program": "${workspaceFolder}/build/Debug/MyPlugin.so",
  "args": [],
  "cwd": "${workspaceFolder}",
  "MIMode": "gdb",
  "coreDumpPath": "${workspaceFolder}/core"
}

4. Analyze: - Call stack shows crash location - Inspect variables at crash time - Identify root cause


Troubleshooting

Issue 1: Breakpoints Not Hitting

Symptoms: - Breakpoint icon hollow (not filled) - Execution doesn't pause at breakpoint

Solutions:

1. Verify Debug Build:

# Check build type
cmake -DCMAKE_BUILD_TYPE=Debug ..

# Verify symbols exist (Windows)
dumpbin /HEADERS MyPlugin.dll | findstr "debug"

# Verify symbols exist (macOS)
dsymutil MyPlugin.vst3

# Verify symbols exist (Linux)
file MyPlugin.so
# Should say: "with debug_info, not stripped"

2. Check Source Matches Binary:

Problem: Code changed but not rebuilt
Solution: Rebuild (Ctrl+Shift+F7 clean rebuild)

3. Verify Debugger Attached:

DEBUG CONSOLE should show:
  Loaded 'MyPlugin.vst3'. Symbols loaded.

If not loaded:
  - Check path to plugin
  - Verify plugin loaded in DAW
  - Try "Attach to Process" instead

4. Check Optimization Level:

# CMakeLists.txt - Debug build should have:
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")  # No optimization

# If -O2 or -O3: Debugger may skip lines
# Solution: Use -O0 for Debug builds

Issue 2: Cannot Attach to DAW

Symptoms: - "Failed to attach to process" error - DAW not in process list

Solutions:

1. Run VS Code as Same User:

Problem: DAW running as different user
Solution: Run both as same user (avoid Admin/sudo)

2. Check Process ID:

# Find DAW process
# Windows
tasklist | findstr Reaper

# macOS
ps aux | grep Reaper

# Linux
ps aux | grep reaper

# Use PID in attach config:
"processId": "12345"

3. Verify Debugger Permissions:

# Linux: May need ptrace permissions
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

4. Try Launch Instead of Attach:

Instead of attaching to running DAW:
- Close DAW
- Use "Debug Plugin (Reaper)" launch config
- Let VS Code launch DAW

Issue 3: Slow Debugging (Stepping Takes Forever)

Symptoms: - F10/F11 takes 5+ seconds - UI freezes during debugging

Solutions:

1. Disable Lazy Symbol Loading:

{
  "symbolLoadInfo": {
    "loadAll": false,
    "exceptionList": "MyPlugin.dll"  // Only load plugin symbols
  }
}

2. Optimize Build for Debugging:

# Balance speed and debugability
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og")  # -Og = optimize for debug

3. Use RelWithDebInfo Build:

# Instead of Debug, use:
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..

# Optimized but with symbols
# Trade-off: Some variables optimized away

4. Reduce Pretty-Printing:

{
  "setupCommands": [
    {
      "text": "-enable-pretty-printing",
      "ignoreFailures": true
    },
    {
      "text": "set print elements 100"  // Limit array size
    }
  ]
}

Issue 4: Variables Show "Optimized Away"

Symptoms: - Variable shows <optimized out> in debugger - Cannot inspect value

Solutions:

1. Use Debug Build (No Optimization):

set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")

2. Mark Variable as Volatile (Temporary):

volatile float myValue = calculateSomething();
// Prevents compiler from optimizing away
// Remove after debugging

3. Use Watch Expression:

Instead of inspecting variable directly:
Add watch: "this->parameterValue"
May show value even if variable optimized

4. Use RelWithDebInfo:

cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo
# Some variables preserved even with optimization

Issue 5: DAW Crashes When Debugger Attached

Symptoms: - DAW starts, then immediately crashes - "Access violation" or segfault

Solutions:

1. Disable Just-In-Time Compilation:

Some DAWs (Logic, Ableton) use JIT
JIT conflicts with debugger
Solution: Disable JIT in DAW settings (if available)

2. Check Code Signing (macOS):

# Debug builds must be signed
codesign -s - MyPlugin.vst3

# Verify signature
codesign -vvv MyPlugin.vst3

3. Disable Address Space Layout Randomization:

# Linux
setarch $(uname -m) -R /usr/bin/reaper

4. Try Different Debugger:

// Instead of cppdbg, try:
"type": "lldb"  // macOS
"type": "cppvsdbg"  // Windows

Best Practices

1. Use Pre-Launch Tasks

Always build before debugging:

{
  "preLaunchTask": "Build: Debug"
}

Benefit: Ensures latest code is debugged.


2. Create DAW Test Projects

Save time loading plugins:

Create: test_projects/debug.rpp (Reaper)
Pre-load plugin on track
Save project
Reference in launch config:
  "args": ["${workspaceFolder}/test_projects/debug.rpp"]

3. Use Conditional Breakpoints

Avoid stopping on every iteration:

for (int i = 0; i < 10000; ++i)
{
    process(i);  // Breakpoint with condition: i == 9999
}

Saves time: Stops only when condition met.


4. Use Logpoints for High-Frequency Code

Audio processing runs 100+ times/sec:

void processBlock(AudioBuffer<float>& buffer)
{
    // Logpoint (not breakpoint):
    // "Processing {buffer.getNumSamples()} samples"

    // Prints to console without pausing
}

5. Organize Configurations by Use Case

Group similar configs:

{
  "configurations": [
    // Plugin Debugging
    { "name": "Debug Plugin (Reaper)" },
    { "name": "Debug Plugin (Logic)" },
    // Test Debugging
    { "name": "Debug Unit Tests" },
    { "name": "Debug Audio Tests" },
    // Advanced
    { "name": "Attach to Process" }
  ]
}

Integration with Tasks

Pre-launch builds (see tasks/README.md):

{
  "name": "Debug Plugin (Reaper)",
  "preLaunchTask": "Build: Debug",  // Runs task before launch
  "postDebugTask": "Clean Up"       // Runs after debug session
}

Task dependency chain:

preLaunchTask: "Build: Debug"
Build task runs
Build completes
Plugin copied to VST3 folder (CMake post-build)
Debugger launches DAW
DAW loads plugin
Breakpoints active


Last Updated: October 2024 Version: 1.0.0 Maintained by: AudioLab DevOps Team

Questions? Ask in #debugging Discord channel or open GitHub issue.