A frontend for the SameBoy Game Boy and Mesen NES / GBA / Master System / Game Gear emulators, with a focus on music creation. It runs standalone and can be used as an audio plugin (CLAP / VST3 / VST2 / AU) in your favourite DAW!
- Five consoles, sniffed from the ROM's own header rather than its file extension: Game Boy / Color (SameBoy), and NES, Game Boy Advance, Master System and Game Gear (Mesen)
- Runs standalone, or as a CLAP / VST3 / VST2 / AU plugin inside your DAW
- Full Game Boy MIDI support for mGB - built in, no ROM needed
- DAW sync for four music carts: LSDj (with Arduinoboy-style modes), risa (NES), smsggdj (Master System / Game Gear), and BlipToaster (NES MIDI synth)
- Song management - browse, load, import, export and reorder the songs inside a tracker cart's battery, without leaving RetroPlug
- ROM assets - swap a cart's sample kits, palettes, themes and fonts, previewed live and patched non-destructively
- Background rendering - bounce a song to WAV from the menu while you keep working, or from the command line without opening the UI at all
- Multiple instances in a single window, linked with virtual Game Boy link cables
- Flexible audio and MIDI routing, including splitting a single system out to its individual sound channels, or a NES out to its three 2A03 output pins
- Real hardware - drive an Everdrive N8 Pro over USB, and use a Novation Launchpad as a control surface
Visit the releases page to download the latest version. Builds are published for Linux (x86_64 and aarch64, so a Raspberry Pi works), Windows (x86_64) and macOS (universal).
- Standalone: the standalone build is a single application that can be placed anywhere you'd like.
- Plugin: copy the plugin into your system's plugin folder, or wherever your DAW
scans for plugins:
- VST3: the platform VST3 folder (e.g.
~/.vst3on Linux,~/Library/Audio/Plug-Ins/VST3on macOS,C:\Program Files\Common Files\VST3on Windows) - VST2: the platform VST2 folder (e.g.
~/.vston Linux,~/Library/Audio/Plug-Ins/VSTon macOS,C:\Program Files\Common Files\VST2on Windows), or wherever your DAW is configured to scan - CLAP: the corresponding
CLAPfolder alongside it - AU (macOS only):
~/Library/Audio/Plug-Ins/Components
- VST3: the platform VST3 folder (e.g.
- Load a ROM by dragging it onto the window, or open the menu and choose
Load.... A.savsitting next to your ROM is loaded automatically. The ROM's console is detected from its header, so a mislabelled file still loads correctly. - Open the menu with
Escape(rebindable) to load ROMs, save your project, and configure everything. Arrow keys navigate,Enteractivates,Escapebacks out. - mGB is built in - pick
Load mGB (GB MIDI Synth)from the start menu and start throwing notes at it. - Your project state is saved into your DAW project when you save. Battery SRAM
can be auto-saved as well - see Settings - or written out manually from
the
Systemmenu. - A music cart gets its own menu. Load LSDj, risa, smsggdj or BlipToaster and a submenu named after the cart appears, holding its sync options, its songs and its assets - see Music Carts.
- Name your project under
Project>Name- it's what the window title and theRecentlist show. Leave it empty (the default) and the name follows the loaded instance instead: its song, sav and ROM. - The
Recentlist remembers songs, not just files. A tracker project gets one row per song you've loaded, so picking a row reopens the project with that song loaded. - Nothing is lost silently. Quitting, or starting / loading another project, with
unsaved work asks first and lists what is unsaved: the project file, and any cart
whose battery differs from its
.sav(naming the file it would write).
Per-instance emulator controls, under System:
- Reset, and Reload on ROM Change - watch the ROM file and reload it when it changes on disk, so an assembler in another window updates the running cart.
- Emulator settings, which differ per console: Model / Fast Boot / Highpass / DMG Palette / Colour Correction / Light Temp (Game Boy), Region / Remove Sprite Limit / APU Latency (NES), FM Audio (Master System).
- Battery and state -
Swap ROM (Preserve SRAM)...,New SRAM...,Load SRAM...,Save SRAM,Load State...,Save State,Save State As.... - Render - bounce this instance to a WAV in the background; see Rendering.
You can load several systems in a single window and work with them side by side - handy for running multiple copies of LSDj (linked with virtual link cables), or a mix of consoles (only Game Boys are linkable). From an instance's menu:
- Add Instance - load another ROM into a new instance.
- Duplicate Instance - clone the active instance, state and all.
- Replace Instance - swap the active instance for a different ROM.
- Remove Instance - remove it from the project.
The Layout option (Auto / Row / Column / Grid) and Zoom control how instances are
arranged and sized. Tab cycles between instances.
Game Boy instances can be wired together with virtual link cables via the
Link Group option - set two or more instances to the same group to link them, the
same way you'd connect real hardware. (The link cable is a Game Boy feature, so the
option only appears on SameBoy instances with a peer.)
By default every instance is summed into a single stereo output. The Audio Routing
option offers:
- Stereo - the default; mixes all instances down to one stereo pair.
- 2 Ch / Inst - each instance gets its own stereo pair (instance 1 → 1-2, instance 2 → 3-4, …).
- 1 Ch / Inst - each instance on its own mono channel.
- Channels - one system's individual sound channels: a Game Boy's 4 channels as four stereo pairs across the 8 outs, or a NES's 5 core channels (square 1/2, triangle, noise, DMC) as mono on outs 1-5.
- Pins - a NES's three 2A03 output pins (Pulse, TND, Expansion) as mono on outs 1-3.
- Stereo Pins - the same three pins, but a stereo pair each (outs 1/2, 3/4, 5/6) with L mirrored to R, so each pin arrives as an ordinary stereo track in a DAW that can only bus or FX whole pairs.
The last three only apply with a single instance loaded, since a split has nowhere to
go once there are peers, and the two pin modes additionally need that instance to be a
NES. The menu offers only what applies, and the audio engine re-checks regardless. In
the standalone, raise Settings > Audio > Out Channels to match, or the extra
streams have nowhere to land.
By default every instance receives all MIDI on all channels. The MIDI Routing
option offers:
- Send to All - the default; every instance receives everything.
- 4 Ch / Inst - four MIDI channels per instance (1-4 → instance 1, 5-8 → instance 2, …). Handy for splitting 16 channels across four mGB instances.
- 1 Ch / Inst - one channel per instance.
- Ch -> Inst - map channels straight onto instances.
RetroPlug recognises four music carts from a marker in the ROM, and gives each one a submenu named after it. What that submenu holds depends on the cart:
| Cart | Console | DAW sync | Songs | Assets |
|---|---|---|---|---|
| LSDj | Game Boy | 8 sync modes, see below | yes | Kits, Palettes, Fonts |
| risa | NES | follows the DAW transport | yes | Kits, Themes, Fonts |
| smsggdj | Master System / Game Gear | follows the DAW transport | yes | not yet |
| BlipToaster | NES | MIDI synth (no sequencer) | - | Kits, Themes, Fonts |
Unlike LSDj, risa and smsggdj need no sync mode picked: they follow the host transport directly, so pressing play in your DAW plays the cart in time.
An unrecognised build of a cart is shown greyed out as (Unsupported Version) rather
than offering rows that would write to addresses it is guessing at.
The Songs submenu lists the songs saved in the cart's battery, and each one can be
loaded, exported, replaced or deleted, with Add... to import from a file and Move
Up / Down to reorder. Everything is done on the cart's own save format, so files stay
readable by the cart, by other tools, and on real hardware.
Loading a song from this menu is what a Recent row replays, and the working song's
name is what the window title shows.
smsggdj is different in one way worth knowing. Its working song lives in the console's work RAM rather than in the battery, and the cart boots to a blank song on purpose. Loading is therefore done live - the song is written straight into the running cart, so nothing is written to disk and the cart is not restarted - but any other battery edit (delete, reorder, import…) does restart it, and RetroPlug warns when that would discard unsaved work.
The asset submenus (Kits, Palettes, Fonts, Themes, depending on the cart) list
what is baked into the ROM and let you replace a slot from a file, in each cart's own
formats - .kit / .lsdpal / .png for LSDj, .rkit / .rit / .chr for risa and
BlipToaster. Replacements are held as overrides and folded into the ROM in memory, so
the ROM on disk is never touched until you ask: Export Patched ROM... writes a
copy, and Patch ROM in Place rewrites the original.
To build a kit from raw audio, use the command line: lsdj-rom, risa-rom and
bliptoaster-rom all have build-kit (compile a kit file from WAVs) and
import-sample (splice one sample straight into a ROM's kit).
When an LSDj cart is loaded, its submenu carries the sync options. Each RetroPlug sync
mode expects LSDj's own SYNC setting (on the PROJECT screen) to be set to match. The
required LSDj setting is noted for each mode below.
- Off - no sync; LSDj plays independently of your DAW. LSDj
SYNC = OFF. - MIDI Sync - LSDj receives MIDI clock from your DAW and plays in time with the
transport. LSDj
SYNC = MIDI. - MIDI Sync (Arduinoboy) - like MIDI Sync, but only starts once a
C-2note is received, emulating the Arduinoboy variation. LSDjSYNC = LSDJ. Requires the Arduinoboy build of LSDj. - MIDI Map - plays rows relative to incoming MIDI notes (
C-0is row 0, and so on). LSDjSYNC = MI.MAP. - Keyboard / Keyboard MIDI - drive LSDj's keyboard input from your keyboard or
from MIDI notes. LSDj
SYNC = KEYBD. - MIDI Passthrough - forwards raw MIDI messages straight to the cartridge over the
link port (the same path mGB uses); no particular LSDj
SYNCsetting is needed. - MIDI Out - LSDj drives the clock and sends its channel notes back out to your
DAW as MIDI. LSDj
SYNC = MI.OUT. Requires the Arduinoboy build of LSDj. - Master Sync - LSDj self-clocks as the master and sends MIDI clock out to your
DAW. LSDj
SYNC = LSDJ.
Three extra controls sit alongside the mode:
- Tempo Divisor - divides the incoming clock for slower/faster sync ratios.
- Auto Start - presses Start for you when the DAW transport starts, so a
SYNC=MIDIcart arms itself automatically. - HD Player - a full-window view of the song, all four chains and all four phrases
at once, drawn in the cart's own font and palette. The cart keeps playing (and stays
playable) underneath;
Escapereturns to the grid.
System > Render bounces an instance to a WAV in the background, from a fresh
copy of its current state - the running instance is never disturbed, and you can keep
working while it renders. The submenu sets the output folder and filename, the split
mode, sample rate, maximum duration and what to do if the file already exists;
Settings > Default Render Dir sets where new renders land by default.
With a loaded LSDj or risa song the length is detected from the song's HFF stop
and the file trimmed to it. smsggdj songs loop forever by design (nothing in that
cart's command set stops the transport), so those need a duration pinned.
The same engine is available from the command line - see below.
Two pieces of physical hardware are supported directly, and their submenus appear only when the device is actually attached:
- Everdrive N8 Pro - load and boot a
.nesonto a real NES over USB, stream live MIDI to it, drive host sync from a MIDI clock, and dump or restore its save. - Novation Launchpad - use a Launchpad as a control surface, with input/output port selection (a Launchpad attached over TRS/DIN arrives under the interface's name, so ports are pickable rather than detected) and a Follow Playhead mode.
The Settings menu covers:
- Audio (standalone only) - driver, output and input device, block size, sample rate, and output channel count.
- MIDI (standalone only) - input device, transport handling, external MIDI clock source, and lookahead.
- Keyboard Bindings / Gamepad Bindings - remap the console buttons and app actions (open menu, cycle instances). Bindings live in named profiles you can create, rename and delete, and both keyboard and gamepad are edited directly in the menu - no config files to hand-edit.
- SRAM Auto-Save - Off, On Save, or Continuous.
- Default Zoom - the zoom applied to new projects.
- Default Render Dir - where background renders are written.
- File Dialogs - the OS-native file dialog, or RetroPlug's in-app browser.
- Open Settings Folder - opens the folder holding your configuration.
The build also produces retroplug-cli (in build/bin/), a self-contained
command-line tool. It runs the same emulator cores as the plugin, so what you hear in a
render matches what you hear in your project, and it needs no Node.js, npm or
node_modules at runtime - the binary is the whole tool.
build/bin/retroplug-cli --help # list the available commands
build/bin/retroplug-cli render --help # options for a command
build/bin/retroplug-cli render song.gbc # LSDj: auto-length stereo mix -> song.wav| Command | What it does |
|---|---|
render |
Render a ROM/SAV to a WAV (full mix or per-channel stems) |
test / run |
Strip and run a directory of TypeScript tests, or a single session file |
lsdj-rom / risa-rom / bliptoaster-rom |
Inspect, extract and patch a cart's kits, palettes, themes and fonts |
n8-load / n8-bridge / n8-sync / n8-play |
Drive a physical Everdrive N8 Pro over USB |
analyze-capture / grab-frame |
Measure a hardware audio capture; grab a NES video frame off a capture card |
launchpad-probe |
Drive a real Launchpad and report what it sends back |
The render command boots a Game Boy (.gb / .gbc), NES (.nes), GBA (.gba),
Master System (.sms) or Game Gear (.gg) ROM and writes its audio to a WAV file. For
a saved tracker song it presses play so the song begins (pass --no-start to capture
raw boot audio); mGB needs no such press, as it plays from incoming MIDI. A sibling
<rom>.sav is loaded automatically if present. Highlights:
- Automatic length - with a loaded LSDj or risa
.savthe song length is detected if the song ends with anHFFcommand, and the render trimmed to it. Otherwise pin a fixed length with--duration 3s(ms/s/m). smsggdj songs have no end to detect, so--durationis required for those. - Per-channel stems -
--split channelswrites one WAV per sound channel (Game Boy: 4 stereo stems; NES: 5 mono core channels), and--split pinswrites the NES analog output pins. The default--split mixwrites a single mixed file. - Song selection -
--list-songsprints the songs saved in a cart's.sav, and--song NAME/--song-index Nrender a chosen one. Works for LSDj, risa and smsggdj; smsggdj boots to a blank song, so one of these is required or the render is silence (it will tell you). - Output control -
--out <file>,--sample-rate <hz>,--bpm <n>with--transportfor tempo-synced playback, and--no-startto capture raw boot audio.
Run retroplug-cli render --help for the full flag reference.
retroplug-cli <session.js> runs a JavaScript session file directly, and
retroplug-cli run <session.ts> runs a TypeScript one - types are stripped in-process,
so no build step and no toolchain are involved. retroplug-cli test <dir> runs a whole
directory of TypeScript tests the same way, which is how a consuming project (a homebrew
ROM, say) can drive the emulator, MIDI and audio analysis in CI with nothing installed
but this one binary.
build.sh (Linux/macOS) and build.bat (Windows) are the canonical entry points -
they run the configure this project needs and build in parallel. You'll need
CMake 3.14+, a C++20 compiler, and Node.js + pnpm (for the UI bundle); the
.devcontainer/Dockerfile has the full dependency list, or
just open the repo in the devcontainer. RetroPlug is developed in a dev container so it
is the recommended approach.
git clone --recursive <repo-url>
cd RetroPlug
pnpm install # wires the deps/dpf.js link before the first configure
pnpm install --dir deps/dpf.js/deps/lv_binding_js # its own workspace; the UI bundle needs it
./build.sh # or: ./build.sh --clean to wipe build/ firstThat second pnpm install is not optional on a fresh checkout: lv_binding_js is a
nested workspace of its own, and without it the UI bundle cannot resolve react.
build.sh passes any -D<var>=<value> straight through to the configure. One worth
knowing: -DRETROPLUG_MESEN_LTO=ON buys about 10% on the NES core and is used for
release builds, but it makes every incremental build re-run link-time codegen, so it is
off by default.
The built artifacts land in build/bin/ (standalone, .clap, .vst3, VST2, AU, and
retroplug-cli).
- SameBoy - accuracy-first Game Boy emulator
- Mesen - accuracy-first NES / GBA / SMS emulator
- DPF - the cross-platform audio-plugin framework (CLAP / VST3 / VST2 / AU / JACK)
- LVGL and lv_binding_js - the UI toolkit and its React/JS bindings
- mGB, LSDj, and Arduinoboy - the Game Boy music software this is all built to serve
Please refrain from asking usage questions in GitHub issues, and use them purely for bugs and feature requests. If you need help, the official support chat for this plugin is on the PSG Cabal discord channel: https://discord.gg/V3GyA5dtqB
Q: HALP! The keyboard does not work ;(
A: All hosts are different, and some have restrictions on routing keyboard input in to VST instruments. First, click the center of the window to try and force the host to give focus to the correct control. If that doesn't work, make sure your host is allowing the plugin to receive keyboard input (Renoise has an "Enable keyboard" option, etc). There are some quirks with certain DAWs...
- Reaper does not send the ctrl key to VST's, so you'll need to remap that to something different.
- Ableton has a bug in their VST2 implementation that strips any information about what key press is actually released (it always returns 0). It is recommended you use VST3 in ableton.
If you find you have issues with a particular DAW, please feel free to submit a bug report.
Q: OMG! LSDj does not start when I hit play in my DAW :o
A: Make sure you have the correct sync mode selected in both LSDj, and in the context menu!
Q: I loaded my smsggdj cart and rendered it, but the WAV is silent.
A: smsggdj boots to a blank song on purpose - it keeps no working song in its
battery. Pick a song first (in the app: the cart's Songs menu; on the command line:
--song / --song-index), and pin a --duration, since its songs loop rather than
ending.
If you'd like to support development of RetroPlug, donations of any amount are appreciated!
MIT
