Skip to main content

Overview

REAPER extensions are DLLs/dylibs that extend REAPER’s functionality. Unlike plugins, extensions:
  • Run in REAPER’s main process
  • Can register custom actions and menus
  • Have full access to REAPER’s API
  • Can show dockable windows
  • Don’t process audio in a plugin chain
REAPER extensions are not audio plugins. They’re for adding features to REAPER itself, like custom tools, utilities, or workflow enhancements.

IPlugReaperExtension Template

The IPlugReaperExtension example demonstrates:
  • Registering actions in REAPER’s action list
  • Creating a dockable UI window
  • Using REAPER API functions
  • Responding to REAPER state changes
  • Adding menu items

Project Structure

Unlike plugins, extensions don’t have config.h with plugin metadata:
config.h
#define PLUG_CLASS_NAME IPlugReaperExtension
#define PLUG_WIDTH 300
#define PLUG_HEIGHT 300
#define PLUG_FPS 60
#define PLUG_SHARED_RESOURCES 0

#define ROBOTO_FN "Roboto-Regular.ttf"
#define SHARED_RESOURCES_SUBPATH "IPlugReaperExtension"
No PLUG_TYPE, PLUG_CHANNEL_IO, or plugin format defines. Extensions aren’t loaded as plugins.

Basic Structure

Creating an Extension

1
Duplicate Template
2
cd iPlug2/Examples
python duplicate.py IPlugReaperExtension MyReaperTool MyCompany
cd MyReaperTool
3
The duplicate script will show a warning about not being able to parse plugin config. This is expected for REAPER extensions.
4
Define Actions
5
Create lambdas for your custom actions:
6
MyReaperTool::MyReaperTool(reaper_plugin_info_t* pRec)
: ReaperExtBase(pRec)
{
  // Import needed API functions
  IMPAPI(GetSelectedTrack);
  IMPAPI(GetSetMediaTrackInfo);
  IMPAPI(SetTrackSelected);
  IMPAPI(UpdateArrange);
  
  // Action: Color selected tracks red
  auto colorRed = [&]() {
    MediaTrack* track = GetSelectedTrack(0, 0);
    if (track) {
      int color = RGB(255, 0, 0) | 0x1000000;  // Custom color flag
      GetSetMediaTrackInfo(track, "I_CUSTOMCOLOR", &color);
      UpdateArrange();
    }
  };
  
  // Action: Show track count
  auto showTrackCount = [&]() {
    int count = CountTracks(0);
    char msg[64];
    snprintf(msg, sizeof(msg), "Track count: %d", count);
    MessageBox(gParent, msg, "Track Info", MB_OK);
  };
  
  // Register actions
  RegisterAction("MyReaperTool: Color Selected Track Red", colorRed, true);
  RegisterAction("MyReaperTool: Show Track Count", showTrackCount, true);
}
7
Import REAPER APIs
8
Use IMPAPI to import functions from REAPER’s API:
9
// Track functions
IMPAPI(GetTrack);
IMPAPI(GetSelectedTrack);
IMPAPI(InsertTrackAtIndex);
IMPAPI(DeleteTrack);
IMPAPI(SetTrackSelected);
IMPAPI(GetSetMediaTrackInfo);

// Item functions
IMPAPI(GetSelectedMediaItem);
IMPAPI(GetMediaItem);
IMPAPI(GetSetMediaItemInfo);

// Project functions
IMPAPI(GetCurrentProjectInLoadSave);
IMPAPI(EnumProjects);

// UI functions
IMPAPI(UpdateArrange);
IMPAPI(UpdateTimeline);
10
You must import every REAPER API function you want to use. If you forget IMPAPI, you’ll get linker errors.
11
Build UI
12
mLayoutFunc = [&](IGraphics* pGraphics) {
  pGraphics->SetLayoutOnResize(true);
  pGraphics->AttachPanelBackground(COLOR_DARK_GRAY);
  
  const IRECT bounds = pGraphics->GetBounds().GetPadded(-10);
  
  // Add controls
  pGraphics->AttachControl(
    new IVButtonControl(bounds.GetGridCell(0, 4, 1).GetMidVPadded(30),
                        [&](IControl* pCaller) {
                          SplashClickActionFunc(pCaller);
                          colorRed();
                        }, "Color Red"));
  
  pGraphics->AttachControl(
    new IVButtonControl(bounds.GetGridCell(1, 4, 1).GetMidVPadded(30),
                        [&](IControl* pCaller) {
                          SplashClickActionFunc(pCaller);
                          ToggleDocking();
                        }, "Dock/Undock"));
};
13
Build and Install
14
Windows
  1. Open .sln in Visual Studio
  2. Build “REAPER Extension” configuration
  3. Output: build-win/MyReaperTool.dll
  4. Copy to C:\Users\[You]\AppData\Roaming\REAPER\UserPlugins\
  5. Restart REAPER
macOS
  1. Open .xcworkspace in Xcode
  2. Build “REAPER Extension” scheme
  3. Output: build-mac/MyReaperTool.dylib
  4. Copy to ~/Library/Application Support/REAPER/UserPlugins/
  5. Restart REAPER
15
Test Actions
16
  • In REAPER: Actions → Show action list
  • Search for “MyReaperTool”
  • Your actions should appear in the list
  • Assign keyboard shortcuts if desired
  • Test Show/Hide UI action
  • REAPER API Access

    Common API Functions

    // Get track count
    int count = CountTracks(0);
    
    // Get track by index
    MediaTrack* track = GetTrack(0, 0);  // Project 0, track 0
    
    // Get selected track
    MediaTrack* selected = GetSelectedTrack(0, 0);
    
    // Get/set track name
    char name[256];
    GetSetMediaTrackInfo_String(track, "P_NAME", name, false);  // Get
    GetSetMediaTrackInfo_String(track, "P_NAME", "New Name", true);  // Set
    
    // Get/set track volume (0.0-4.0, 1.0=0dB)
    double volume;
    GetSetMediaTrackInfo(track, "D_VOL", &volume);  // Get
    volume = 0.5;  // -6dB
    GetSetMediaTrackInfo(track, "D_VOL", &volume);  // Set
    
    // Get/set track pan (-1.0 to 1.0)
    double pan = 0.0;
    GetSetMediaTrackInfo(track, "D_PAN", &pan);
    
    // Select/deselect track
    SetTrackSelected(track, true);
    

    API Documentation

    Full REAPER API reference:

    Action Registration

    Action Types

    // Simple action (no state)
    RegisterAction("MyTool: Do Something", doSomething);
    
    // Action with menu item (checkmark in menu)
    RegisterAction("MyTool: Toggle Feature", toggleFeature, true);
    
    // Action with toggle state
    int state = 0;
    RegisterAction("MyTool: Show Window", showWindow, true, &state);
    // state will be read to show checkmark in menu
    

    Action Descriptions

    Action Naming Convention:
    • Start with extension name: "MyTool: ..."
    • Use descriptive verbs: Show, Hide, Toggle, Add, Remove
    • Keep under 80 characters
    • Use title case

    Window Docking

    // Toggle docking state
    ToggleDocking();
    
    // Check if docked
    if (IsDocked()) {
      // Window is docked
    }
    
    Users can:
    • Dock to left/right/bottom of REAPER window
    • Float as separate window
    • Save dock state with REAPER project

    Example Extensions

    Track Organizer

    class TrackOrganizer : public ReaperExtBase
    {
    public:
      TrackOrganizer(reaper_plugin_info_t* pRec) : ReaperExtBase(pRec)
      {
        IMPAPI(CountTracks);
        IMPAPI(GetTrack);
        IMPAPI(GetSetMediaTrackInfo_String);
        
        auto sortByName = [&]() {
          int count = CountTracks(0);
          std::vector<std::pair<std::string, MediaTrack*>> tracks;
          
          for (int i = 0; i < count; i++) {
            MediaTrack* track = GetTrack(0, i);
            char name[256];
            GetSetMediaTrackInfo_String(track, "P_NAME", name, false);
            tracks.push_back({name, track});
          }
          
          std::sort(tracks.begin(), tracks.end());
          
          // Reorder tracks (would need more API calls)
          ShowConsoleMsg("Sorted tracks by name\n");
        };
        
        RegisterAction("TrackOrganizer: Sort Tracks by Name", sortByName, true);
      }
    };
    

    Batch Processor

    auto batchNormalize = [&]() {
      int count = CountTracks(0);
      
      for (int i = 0; i < count; i++) {
        MediaTrack* track = GetTrack(0, i);
        
        // Analyze peak
        double peak = AnalyzeTrackPeak(track);
        
        // Set volume for normalization
        if (peak > 0.0) {
          double volume = 1.0 / peak;
          GetSetMediaTrackInfo(track, "D_VOL", &volume);
        }
      }
      
      UpdateArrange();
      ShowConsoleMsg("Normalized all tracks\n");
    };
    

    Building

    Visual Studio (Windows)

    Configuration: REAPER Extension
    Platform: x64
    Output: build-win/MyReaperTool.dll
    

    Xcode (macOS)

    Scheme: MyReaperTool - REAPER Extension
    Architecture: Universal (Intel + Apple Silicon)
    Output: build-mac/MyReaperTool.dylib
    

    Troubleshooting

    1. Check file is in correct UserPlugins folder
    2. Restart REAPER
    3. Check REAPER console (View → Show REAPER console) for errors
    4. Verify correct architecture (x64 for Windows, Universal for macOS)
    1. Verify RegisterAction was called in constructor
    2. Check REAPER console for registration errors
    3. Search for exact extension name in action list
    1. Did you call IMPAPI(FunctionName) to import it?
    2. Check function signature matches REAPER docs
    3. Verify REAPER version supports that API
    1. Use SetLayoutOnResize(true) in layout function
    2. Implement proper bounds handling for resize
    3. Test dock/undock with ToggleDocking()

    Next Steps

    REAPER API Docs

    reaper_plugin_functions.hComplete API reference

    REAPER Plugins

    Build audio plugins that integrate with REAPER API

    IGraphics

    Customize extension UI

    Examples

    Browse more REAPER extensions