Skip to content
sambenaPublic

About

Swap game music in RetroArch while keeping sound effects: SNES, NES and N64 (Super Mario 64, Ocarina of Time). A libretro wrapper core, DSP plugin, and Proteus Studio for finding and mapping songs.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

218 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Proteus Retune

A RetroArch audio plugin and libretro core that swap a game's soundtrack while keeping its sound effects.

Proteus works alongside an existing core (Snes9x, Genesis Plus GX, Mesen, ...). Per game it:

  1. watches a RAM address to learn which song the game is playing,
  2. mutes the original music through the core's per-channel volume options,
  3. mixes in replacement music, with crossfades and loop points. The replacement can be
    • a recording: WAV, MP3 or Ogg Vorbis, or
    • another game's music on its original sound chip, emulated by libgme: SNES .spc, NES .nsf/.nsfe, Genesis/Master System .vgm/.vgz/.gym, Game Boy .gbs, PC Engine .hes, MSX .kss, ZX Spectrum .ay and Atari .sap, or Nintendo 64 .usf/.miniusf rips (with their .usflib), emulated by lazyusf2.
    • Nintendo DS rips: .2sf/.mini2sf (with their .2sflib), emulated by vio2sf, and .ncsf/.minincsf (with their .ncsflib), sequences played by SSEQPlayer.
    • streamed music from the GameCube onward, decoded by vgmstream: GameCube and Wii .dsp (a _L/_R pair plays as one stereo song), .idsp, .mdsp, .adp, .ast, .hps, .thp, .bns, .brstm, .brwav, .rwar; 3DS, Wii U and Switch .bcstm, .bcwav, .bfstm, .bfwav, .bwav; DS .strm, .swav; CRI .adx, .aax, .hca. Not looped, a stream plays its loop twice and fades out over ten seconds.

Proteus comes in two forms that share profiles and music files:

DSP plugin Wrapper core
Use with any core, unchanged — keep choosing Snes9x a separate core entry, e.g. "Proteus Retune + Snes9x"
Turn on Settings → Audio → DSP Plugin → Proteus.dsp (or a per-core/per-game override) load the game with the wrapper core
Muting the original music for the whole game: the profile's [mute] options are saved as RetroArch game options (by Generate INI, or by the plugin the first time the game runs, which then needs the game loaded again) song by song, automatically
Settings the profile; song changes are logged to logs/proteus.log Quick Menu → Core Options → Proteus Retune, with per-song pickers and on-screen song values
Save states music follows the song detected after loading music position is saved in the state

When the wrapper core is running, the plugin stands aside. Games without a profile play exactly as they would without Proteus.

For the Atari 2600 the wrapper core also draws the picture anew and gives the games new sounds: see Atari 2600: picture and sound.

Pitfall! with the effects off and with Proteus

Download

Windows builds are on the Releases page. Unzip, close RetroArch, and run the installer from the unzipped folder (see Install); READ ME FIRST.txt has the commands. No games, ROMs or music are included.

Build

From an MSYS2 UCRT64 shell (pacman -S make mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-SDL2):

make          # build/proteus_dsp.dll (plugin) and build/proteus_libretro.dll (wrapper core)
make studio   # build/ProteusStudio.exe (song discovery and profile mapping GUI)
make cli      # build/proteus-cli.exe (Studio's scans and reference songs from the command line)
make test     # runs the headless test suite (needs sox for the test assets)
make ZLIB=0   # without compressed .vgz support

ProteusStudio.exe and both DLLs link their C++ runtime, zlib, and dependencies statically, so they only need Windows' own runtime libraries.

Install

Close RetroArch, then from the release folder (or tools\ in a source checkout):

powershell -ExecutionPolicy Bypass -File .\install-core.ps1 -RetroArch C:\RetroArch-Win64 -Dsp            # plugin
powershell -ExecutionPolicy Bypass -File .\install-core.ps1 -RetroArch C:\RetroArch-Win64 -Core snes9x    # wrapper core
powershell -ExecutionPolicy Bypass -File .\install-core.ps1 -RetroArch C:\RetroArch-Win64 -Core fceumm    # wrapper core for NES

tools/package-release.sh <version> builds everything and packs the release zip.

Plugin: copies proteus_dsp.dll and a Proteus.dsp preset to filters\audio. Select it under Settings → Audio → DSP Plugin. It finds the running core inside RetroArch and the running game from RetroArch's content history, so history must be enabled (the default).

Wrapper core: Proteus chooses the core to wrap from its own file name: proteus_snes9x_libretro.dll wraps snes9x_libretro.dll in the same folder. The script also creates a .info file, so RetroArch lists Nintendo - SNES / SFC (Proteus Retune + Snes9x). Load a game with that core instead of Snes9x itself.

Core options (wrapper core)

Proteus adds a Proteus Retune category next to the wrapped core's own options:

Option Values
Music replacement Enabled / Disabled
Replacement music volume Profile default, 0–200%
Game audio volume Profile default, 0–200% (everything the game plays, including sound effects)
Crossfade Profile default, Off, 100–2000 ms
Song change notifications Profile default, Enabled / Disabled; shows each song value on screen
Song 0x05, Song 0x06, ... Profile default, Original music, Silence, or any playable file

The song pickers appear for every song listed in the game's profile. They list the files in the profile's [library] folders and in the folders its tracks come from; multi-song files such as NSF appear once per song (dungeon.nsf #3).

Changes apply immediately. Use RetroArch's Manage Core Options → Save Game Options to keep them for one game only.

Proteus Studio

Proteus Studio (make studio, SDL2 + Dear ImGui) builds a profile from two SNES or NES ROMs: the game to change and a game to take music from. It needs RetroArch's snes9x core for SNES games and its FCEUmm core for NES games (see NES games).

  1. Open the game to change on the left and the music source on the right (or drop ROMs on either side).

  2. Scan songs on each side. Studio starts the game, sends every song number through the game's music command from that moment, and rips whatever the sound chip plays to an .spc file. Values that change nothing, repeat an earlier song (even shifted in time), or stay silent are dropped; short songs are marked as jingles. Rips are kept in %APPDATA%\ProteusStudio\library, so a ROM opens with its songs next time.

    When it is not known how the game starts songs, or the known way starts none, the scan finds out first. It watches the game boot and, each time a command goes to the sound CPU, notes the RAM bytes copied to its ports and the calls left on the CPU stack. It then tries, with a few song numbers each:

    • writing each command it saw back to RAM for the game to send (A Link to the Past: $012C = song), and
    • calling each routine it saw with the command in RAM or the song number in A, by pointing the CPU at a few instructions in spare RAM (Chrono Trigger: JSL $C70004 with $1E00 = 10 song FF 05),

    and keeps the one that starts the most different songs. With reference songs for the game (below), each rip is named after the song it matches, only real songs are kept, and a way of starting songs counts only when it starts at least two different reference songs.

  3. Click play on any song, from either game, to listen. Rips play from the sound chip state, with their own loops.

  4. For each song of the game to change, pick a replacement (or drag one from the right), or Silence, or any music file.

  5. Generate INI writes the profile to the game's existing profile or system/proteus/<game>.ini, and copies the chosen songs to system/proteus/music/<game>/. A profile that Studio did not write is first saved as <game>.ini.bak.

Songs are numbered by the song address Proteus follows while the game runs. Before ripping, a scan starts a few songs and reads all of work RAM back: a byte that holds exactly the song started, and keeps it, is where the game records it (A Link to the Past: $0130). Addresses from the game database, RetroAchievements notes and static analysis are preferred when they pass this check; one that fails is not used. When no byte keeps the song number, the command itself becomes the song address (Super Mario World: $1DFB; Chrono Trigger: $1E00 = 10 song .. .., where .. matches the bytes that change from song to song).

Rips are taken at a song's first notes when the game goes quiet while it loads the song, so they play from the start.

Reference songs

A game's soundtrack as .spc files, from an archive such as SNESmusic.org or Zophar's Domain, makes Studio's results reliable. Each .spc holds the sound CPU's memory while its song plays, including the song's data. Add them per game with Reference songs:

  • Download finds the game's set on Zophar's Domain, or else on SNESmusic.org, by the ROM's file name and the game's title. Names are compared by their words, so "Legend of Zelda - A Link to the Past, The (USA)" finds "Legend of Zelda: A Link to the Past".
  • Import folder... or Import archive or .spc... copies a set you downloaded. Dropping a folder, an archive or .spc files on a panel does the same. SNESmusic.org's .rsn sets, and .rar and .7z archives, are opened with 7-Zip, which must be installed.
  • List reference songs adds every reference to the list without playing the game. That is all a music source needs.

Sets are kept in %APPDATA%\ProteusStudio\reference\<ROM CRC32>.

Naming rips. A rip is compared with every reference, counting only the sound CPU memory that changed since the song was started, so what an earlier song left behind does not count. Data that many references hold (instrument samples, which load wherever there is room) counts for little; data only one song holds counts for much.

Some sound drivers (Super Mario World's) load a whole group of songs at once and start one by moving a pointer, so little memory tells those songs apart. Studio also listens: it measures how strongly each of the 12 notes sounds over a song's first 30 seconds, and lines the rip up with each reference wherever they match best (sets are often dumped seconds into a song). A weak memory match is kept only when the rip's notes rank that song among their closest three, and a rip no memory matches is named when its notes match one reference almost exactly, well ahead of any other song. A rip that is the music already playing, exactly as far along as the time that passed, changed nothing and is not named; the same song started over lines up differently and is. Super Mario World's overworld songs are named this way. A scan names each song after its reference and uses the reference's .spc, which plays the song from its start. Songs that match no reference are marked no match.

Song tables. Many games keep their songs uncompressed in the ROM, with a table of pointers to them. When the references' song data is found in the ROM and a table points to most of it, Studio reads the song numbers from the table (entry 0 is where the game's code reads it). Scan songs then lists every song of the table by name at once, plays the table's song numbers, and checks each one against its reference. Chrono Trigger's table is at $C70D18: 83 songs, all named by the SNESmusic set.

NES games

NES games work the same way in Studio, with these differences:

  • Rips are recordings. The NES plays its music on the main CPU, so there is no sound chip state to save: a rip is 20 seconds of what the game plays, kept as a .wav file.
  • Reference songs are .nsf sets. Download finds the game's set on Zophar's Domain; its .m3u playlist names the songs (a set without one lists every song of the .nsf by number). Rips are named by their notes alone, and a song named by a reference plays from the .nsf, looping as the game does.
  • Finding how songs start. An .nsf holds the game's own music code, and many rips start a song the way the game does, by writing a request to RAM. Studio runs the .nsf's init routine for every song on a small 6502 and notes the RAM each writes (The Legend of Zelda: $0600 = 80 for the title, 01 for the overworld). Those bytes are tried first; when one starts songs in the game, the values the .nsf writes are the game's songs: they are listed by name at once, and only they are played to check them. Otherwise the scan watches the RAM while the game starts up, and writes each byte that takes a few values from a moment music plays (many games play none on their title screen), keeping the bytes after which the game sounds different. Super Mario Bros. asks for songs through $FB, which it reads as bits, and keeps the song playing at $F4; a song it plays under many numbers is listed under its first number and single bits.
  • Watching the .nsf's song RAM in the game. Writing a request from outside does not always start a song (the game may read it only at certain moments), but the game still uses the same RAM. From power-on, with Start tapped now and then, the scan watches every byte the .nsf writes with its songs' values. A byte that takes them, each either cleared at once (a request: Metroid $0684, Punch-Out!! $00F0) or held while the song plays (Castlevania $0082), and never swaps one for another within a second, becomes the song address, and the set's songs are listed by those values. Requests are used before a tap; a held byte, which may be channel state that sound effects also change, only when no tap works.
  • A tap on the sound routine. Much music code keeps no song number anywhere: Mega Man 3's .nsf starts a song by calling the game's "play this sound" routine ($8106) with the song in A. The rip's code is the ROM's own, so Studio taps that routine with cheat codes: its first instructions move to a stub in blank ROM, which writes each request + 1 to a RAM byte no code names and the game leaves alone, then carries on into the routine. The scan checks the tap reports one of the .nsf's songs in the game; that byte becomes the song address (latch = 1), every song of the set is listed by the value the game requests it with, and sound effects, which the tap reports too, are left unlisted (unmapped = keep). Profiles carry the tap in a [tap] section, on for the whole game. Taps are FCEUmm cheat codes, so they need FCEUmm. Games found neither way can be played with Play & rip (R rips the music playing), which names the songs heard and, after three or more, can learn the song address as it does for SNES games.
  • Stopping the music, keeping the sound effects. Most NES games play sound effects on the music's channels, so muting channels loses them. After a scan, Studio writes each value of the song request while music plays and keeps one that stops the music (Super Mario Bros.: $FB = 80); profiles then carry a [silence] section instead of channel mutes, and Proteus writes that request whenever replacement music starts. The RAM that holds the song playing then reads the silence, so profiles follow the requests instead: the song request ($FB, latch = 1) and the register the .nsf starts its other songs with, as jingles (events = 0x00FC: the death jingle is song 0x101), so the game's own jingles stop the replacement. The .nsf also shows how to stop the music code itself: Studio skips each call and flips each branch its play routine runs, and keeps a change that silences the music songs while the .nsf's sound effects keep sounding, when the ROM holds that code (Mega Man 3: 809D D0 → F0). A patch that silences the .nsf can still leave a note hanging in the game, so each is heard there too, from a moment a song starts over another, and kept only when the game goes quiet (Mega Man 2's first candidate left 83% of the sound; 8269 leaves none). Profiles carry it as a [patch] cheat code, applied only while replacement music plays. Games with neither (The Legend of Zelda so far) fall back to muting channels: FCEUmm switches each of the NES's five channels on or off (fceumm_apu_1 .. _5: two squares, triangle, noise and samples), and Studio mutes the squares and triangle by default. The DSP plugin saves those mutes as game options, which stay off for the whole game.
  • TAS movies are SNES only for now.

Progress. Scan folder over 100 popular NES games, with FCEUmm and Zophar's .nsf sets:

Games
Song address found and at least 3 songs named 78 (17 before the watch, taps and 6502 fixes)
... through the .nsf's song RAM watched in the game 41
... through a tap on the sound routine 21
... through RAM that starts songs, or the song finder 16
Music stopped with a code patch, sound effects kept 23
Music stopped with a RAM request, sound effects kept 12
Partly (no song address, or fewer than 3 songs named) 17
Skipped (no .nsf set, or the ROM did not open) 5

A found song address is not a game heard working: Super Mario Bros., Mega Man 2, Mega Man 3 and Castlevania have been played through the wrapper core with replacements, the game's music stopped and its sound effects kept. Still partly: Contra, Zelda II, Tetris, Gradius, Dragon Warrior, Faxanadu, Life Force, Kung Fu, Pac-Man, Paperboy, Rad Racer, R.B.I. Baseball, Kickle Cubicle and Top Gun (1943, Duck Tales 2 and Shadow of the Ninja have no set on Zophar's Domain).

N64 games

Choose Mupen64Plus-Next as the N64 core in Settings, then open Super Mario 64 or Ocarina of Time (any revision). Studio lists every background song by number and name at once; N64 games need no song scan in the SNES sense.

  • Scan songs runs the game for a few seconds to find its sequence players (see N64 games below). Opening a game whose profile already follows them skips this.
  • Reference songs > Download fetches the game's USF set from Zophar's Domain. Each song then plays its rip, and the set's other tracks (variations, fanfares) are listed without numbers, so an N64 game makes a music source for any other game too.
  • Generate INI writes the profile with the replacements chosen. A .miniusf used as a replacement is copied with its .usflib.

Play & rip, TAS movies and Scan folder are for SNES and NES games. Fanfares that Ocarina of Time plays over the music (item gets, ocarina songs) stay the game's own and are not listed.

TAS movies

Games whose songs a scan cannot start from outside (ActRaiser 2 uploads each song itself) can still be worked out by playing them through. TASVideos publishes movies that play whole games, and TAS movie on either panel (Advanced > TAS movie) uses them:

Play movie and find songs does every step that is missing, in order; the steps can also be done one at a time:

  1. Download BizHawk installs the latest BizHawk release into %APPDATA%\ProteusStudio\tools\BizHawk. Movies only stay in sync on the emulator they were made with: on snes9x, or on libretro's bsnes cores, a movie falls out of step within minutes. BizHawk needs .NET Framework 4.8 and the Microsoft Visual C++ runtime.
  2. Find movies on TASVideos lists the game's publications; Download saves a BizHawk movie (.bk2) to %APPDATA%\ProteusStudio\movies\<ROM CRC32>. Open movie file... adds one you have. The movie must be for the same version of the ROM.
  3. Play movie and find songs plays it in BizHawk, as fast as the computer allows up to the speed chosen (most SNES movies run 5 to 8 times faster than real time). A Lua script saves the sound CPU's memory and work RAM every 2 seconds. Each moment is named against the reference songs, and a moment counts only when the moments on both sides of it name the same song. The work RAM byte that holds one value for each song, and a different value for every song, becomes the song address (saved to the game database), and the songs heard join the list with their numbers.

ActRaiser 2's movie hears all 15 reference songs in six and a half minutes and numbers 13 of them by $0028. Games that pass songs through a command and keep no song number (Chrono Trigger) have their songs named, but no address is found this way.

Scan folder

Scan folder in the header scans every ROM in a folder, one after another: it downloads each game's reference songs, runs Scan songs, and, when asked and BizHawk is installed, plays a TAS movie for games the scan could not number. Each game is rated easy (a song address and at least three songs named by reference songs), partly (songs or reference songs, but not both working) or skip. Results go to the song libraries and the game database as a scan in the window would, and to a report in %APPDATA%\ProteusStudio\folder-scans; a stopped scan carries on where it left off. Double-click a game to open it.

Game database

What Studio learns about a game is kept in %APPDATA%\ProteusStudio\games.ini, one section per ROM CRC32 (without a copier header), so each game is worked out once:

[2D206BF7]
name = Chrono Trigger
song_address = system_ram 0x1E00 bytes=10 xx .. .. latch=1 debounce=1
start = routine jsl 0xC70004 block=0x1E00 bytes=10 xx FF 05 settle=300
note = confirmed by a scan 2026-09-13

[B19ED489]
name = Super Mario World
song_address = system_ram 0x1DFB size=1 latch=1 debounce=1
start = ram 0x1DFB bytes=xx settle=150

start says how songs are started: ram <address> bytes=<command> writes a command the game sends itself; routine <jsl|jsr> <address> [block=<address> bytes=<command>] [a=song] calls the game's music routine. xx marks the song number; settle is how many frames a song gets before it is ripped. Scans and the song finder write the file; it can also be edited by hand or under Advanced > Game info (which also includes RetroAchievements lookup to query documented BGM addresses by ROM hash). Super Mario World, A Link to the Past and Chrono Trigger are built in.

The Advanced tabs:

Advanced tab Use
Play & rip Play either game. Whenever the game sends the sound CPU a command, or the song address changes, the new song is ripped once it has started (repeats are skipped); Rip current song (R) rips whatever plays. Scan from this moment makes later scans start there, for games that load music per world or level. With reference songs, play also learns the song address: every 2 seconds the song playing is named, and RAM that does not hold one value per song is ruled out; when one byte is left after three songs or more, it becomes the song address and the rips are numbered by it (A Link to the Past: $0130 is among the last bytes left after three songs). For games that choose their music in their own logic and upload each song (ActRaiser 2), which no scan can start, this or TAS movie is the way.
TAS movie Play a TASVideos movie of the whole game in BizHawk to hear its songs and learn the song address (see TAS movies). Play movie and find songs does every missing step.
Find song address Press Music changed (M) right after the music changes and Same music (N) when it does not; the song and command bytes remain.
Game info The song address, how songs start, and the scan range, saved to the game database.
Channels & mix The channels muted while replacements play, and the mix volumes.
INI preview The profile Generate INI will write.

Game controls in Advanced: arrow keys or a controller; Z/X B/A, A/S Y/X, Q/W L/R, Enter Start, Right Shift Select; P pause, Tab fast forward, F2/F4 save/load state.

A RAM command only finds songs whose music data is loaded at the scan's starting moment; a music routine loads each song itself. Games whose songs start some other way (Super Metroid and ActRaiser queue them; Mega Man X was not found either) cannot be scanned yet: play them with Play & rip or TAS movie, or add a start line to the game database once it is known.

Game profiles

Proteus looks for a profile in this order:

  1. next to the ROM: Super Game (USA).proteus.ini
  2. in RetroArch's system folder: system/proteus/Super Game (USA).ini

Paths are relative to the profile. Lines starting with ; or # are comments; after a value, ; starts one (a # there is part of the value, as in music/Stage #1.ogg). A file name holding ; or | goes in double quotes: 0x05 = "music/Act 1; Part 2.ogg" | loop=0.

[song]
memory   = system_ram   ; system_ram | save_ram | video_ram | rtc
address  = 0x1234       ; offset of the "current song" value
size     = 1            ; 1, 2 or 4 bytes, little endian (ignored when bytes is set)
bytes    = 10 xx .. ..  ; optional: multi-byte command block pattern; xx is the song, .. any value
mask     = 0xFF         ; optional
debounce = 2            ; frames a new value must hold before it counts
latch    = 1            ; optional: address is a command register (ignores 0, keeps playing last song)
events   = 0x00FC       ; optional: a second command register for jingles, read as song 0x100 + command
unmapped = original     ; what unlisted values do: original | silence | keep
byte_order = n64        ; optional: N64 addresses in RDRAM kept as host-order 32-bit words (Mupen64Plus)
active   = 0x80128B60 & 0x80 ; optional: while these bits are clear no song plays (a sequence player's flag)
stopped  = original     ; what a clear `active` flag does: original | silence | keep

[mute]
; Core options forced while replacement music (or silence) is active.
snes9x_sndchan_volume_1 = 0
snes9x_sndchan_volume_2 = 0

[silence]
; Optional: a request written to RAM that stops the game's own music while replacement music
; (or silence) is active, instead of muting channels, so sound effects keep playing.
memory   = system_ram
address  = 0x00FB       ; Super Mario Bros.
value    = 0x80

[hold]
; Optional: RAM written before every frame while replacement music (or silence) is active, silencing
; the game's music player; sound effects play on. Values are hex bytes (big endian with
; byte_order = n64). After a comma, what is written back when the mute lifts (by default, what was
; there); |= sets bits, and sets them once more after the mute (a "recalculate volume" flag).
0x80128B8C = 00000000, 3F800000   ; Ocarina of Time: the BGM player's volume scale
0x80128B60 |= 04

[patch]
; Optional: cheat codes, per core, that stop the game's music code while replacement music (or
; silence) plays, keeping its sound effects. A core's lines are joined with '+'.
fceumm = 809D?D0:F0     ; Mega Man 3

[tap]
; Optional: cheat codes, per core, on for the whole game, that make it report what it asks its
; sound routine to play at the song address (see NES games).
fceumm = 8106?C9:4C+8107?F0:1E+8108?90:8A+8A1E?00:08+8A1F?00:48+8A20?00:18+8A21?00:69+8A22?00:01
fceumm = 8A23?00:8D+8A24?00:FC+8A25?00:07+8A26?00:68+8A27?00:28+8A28?00:C9+8A29?00:F0+8A2A?00:B0
fceumm = 8A2B?00:03+8A2C?00:4C+8A2D?00:0D+8A2E?00:81+8A2F?00:4C+8A30?00:0A+8A31?00:81

[mix]
music_volume = 100      ; percent, up to 200
game_volume  = 100
crossfade_ms = 400

[library]
; Folders offered in the song pickers (tracks' own folders are always included).
dir = music
dir = ../Other Game/spc

[tracks]
; song value = file | options
0x01 = music/title.ogg
0x05 = music/overworld.ogg | loop_start=264600
0x06 = ../Other Game/spc/boss.spc
0x07 = music/fanfare.wav | loop=0
0x08 = music/soundtrack.nsf | track=4
0x09 = silence
0x0A = original

[debug]
log_songs = 1           ; log and show every song change on screen

Track options:

Option Meaning
loop 1 (default) loops the track; 0 plays it once. Emulated tracks without a tagged length keep playing.
loop_start sample frame the loop returns to (recordings)
volume percent, up to 200
track song number inside a multi-song file (NSF, NSFE, GBS, HES, KSS, AY, SAP), starting at 1
name what the game's song is, shown in the Quick Menu song pickers (0x02 = original | name=Hyrule Field)

Emulated music plays at the wrapped core's sample rate, so an SPC under snes9x needs no resampling.

Finding the song address

The easiest method is using Proteus Studio (make studio), which narrows down candidates automatically as you mark song changes while playing, or sweeps command registers across a save state.

Alternatively, use a RAM search tool (RetroArch's cheat search, or the memory viewer in Mesen, bsnes-plus or RetroAchievements' RAIntegration): note values in one music area, move to an area with different music, and keep the addresses that changed. Then put the candidate in [song] address, turn on Song change notifications, and watch the on-screen values while walking between areas.

For SNES, system_ram is the 128 KB work RAM, so address $7E0ABC becomes 0x0ABC. For NES it is the 2 KB of RAM at $0000-$07FF. For N64 (Mupen64Plus-Next) it is the 8 MB of RDRAM; with byte_order = n64, write addresses as the game sees them (0x80222618).

N64 games (Nintendo EAD sound engine)

Super Mario 64 and Ocarina of Time play music with sequence players: structures in RAM with the sequence (song) number, a playing flag and volumes, one player for background music and others for fanfares and sound effects. The profile follows the BGM player's sequence number and holds its volume at zero while replacing, so the sound effects on the other players are untouched.

Game Player Song Playing flag Silence it
Super Mario 64 (USA) 0x80222618 (size 0x140) +0x05 +0x00 & 0x80 fade volume +0x18 = 00000000, 3F800000
Ocarina of Time (USA 1.0) 0x80128B60 (size 0x160) +0x04 +0x00 & 0x80 volume scale +0x2C = 00000000, 3F800000 and +0x00 |= 04 (recalculate)

The addresses move between revisions (Ocarina of Time Rev 1: 0x80128D20, Rev 2: 0x80129430), so let proteus-cli find them and write the profile, every song listed by name:

proteus-cli n64 <cores\mupen64plus_next_libretro.dll> <ROM or ROM folder> <system\proteus> [--force]

Sequence numbers are the decompilations' (seq_ids.h in n64decomp/sm64, sequence_table.h in zeldaret/oot): Ocarina of Time's title is 0x1E, file select 0x57, Hyrule Field 0x02.

Muting the original music

When the game's music can be stopped through its RAM, a [silence] section does that and no channel needs muting. Otherwise the mute options are core-specific:

Core Options Mute value
snes9x snes9x_sndchan_volume_1 .. _8 0
FCEUmm (NES) fceumm_apu_1 .. _5 (square 1, square 2, triangle, noise, samples) disabled
Genesis Plus GX genesis_plus_gx_md_channel_0_volume .. _5 (FM, MAME FM emulators only), genesis_plus_gx_psg_channel_0_volume .. _3 0

Sound effects in most SNES games use the upper voices (often 7 and 8), so muting voices 1–6 usually keeps them. Games that steal music voices for effects will lose some effects; mute fewer channels for those games.

Atari 2600: picture and sound

Around Stella, the wrapper core draws the picture again from the objects the TIA made it of, and processes the TIA's two voices apart. None of it needs to know the game. Twenty games it does know get more: see Games Proteus knows.

Space Invaders Pac-Man
River Raid Missile Command
Pole Position Kaboom!
Adventure Pitfall!

In each pair the left is the game with the effects off and the right is what Proteus draws. No games or ROMs are included.

Effect What it does
Glow players, missiles and the ball glow in their own colour; in the games Proteus knows the score and lines such as a road's kerbs give off none and stay crisp
Shot trails missiles and the ball leave a fading trail
Shadows objects throw a shadow on the playfield and the background
Smooth objects the stair steps of objects are cut; the playfield stays blocky
Flicker fusion objects the game shows in turns are drawn in every frame
Background treatment a vignette, and bands of background colour blend into each other
Fill the bars at the left the black bars of lines on which a game moved its objects (HMOVE) get the scenery next to them
Stereo width the two voices are panned apart
Low-pass filter, reverb each voice is filtered, and both get a room around them

This needs a build of Stella that reports what each pixel is made of: the proteus-capture branch of sambena/stella, a fork of Stella that builds stellapx_libretro. Around Stella as its authors build it, the picture passes through unchanged and the sound is processed as one voice.

From an MSYS2 UCRT64 shell:

git clone --branch proteus-capture https://github.com/sambena/stella.git
make -C stella/src/os/libretro
cp stella/src/os/libretro/stellapx_libretro.dll /c/RetroArch-Win64/cores/
cp /c/RetroArch-Win64/info/stella_libretro.info /c/RetroArch-Win64/info/stellapx_libretro.info

Then install the wrapper around it, which RetroArch lists as "Atari - 2600 (Proteus Retune + Stella)":

.\tools\install-core.ps1 -RetroArch C:\RetroArch-Win64 -Core stellapx

The fork also makes two of Stella's core options do what they say, which Proteus relies on: Stereo sound "on" gives the two voices apart, and Phosphor mode "off" is off from the start of a game.

The options are under Proteus 2600 in the core options. View shows the picture's parts: every object in a flat colour of its own, one layer alone, or a box around every object found, which is how to see what a game draws with which object. Picture size "Native" is Stella's own frame, for shaders that draw scanlines themselves.

A game's profile can set any of the options, for where they are left at "Default":

[fx]
glow = high
flicker = disabled
width = 60

A profile with [fx] and no [song] swaps no music.

Changing the options while playing

Button (RetroPad X) Keys
The list of the options on the picture; the game stands still tap \
In the list: choose, change, back to the game up and down, left and right, fire
The option before, the one after hold, and left or right [ ]
Change it hold, and up or down - =
The enhanced picture on and off, to compare hold, and fire 1
What Proteus knows of the game on and off hold, and the second button 2
Glow, shadows, smooth objects, flicker fusion, trails, background, scanlines, view 3 to 0

A line on the picture says what changed. The options change at the frontend too, where they are kept, if it takes changes from a core (RetroArch does); else until the game ends. While the button is down the game sees none of the buttons. Button for the options and Keys for the options turn either off: Stella takes X to load the next game with its "reload" option on, and the digits belong to the keyboard controllers in the games played with those.

Games Proteus knows

Proteus finds a game by the MD5 of its ROM, as Stella does, and draws the games it knows with what it knows of them. Their options come after Picture size, and the first of them, named after the game, turns all of it off.

Game ROM What Proteus does
Space Invaders 72ffbef6504b75e69ee1045af9075f66 (USA) a colour for every row of invaders, or the white, red and green of the arcade cabinet's gels; a night sky where the game is black; the score drawn solid, which the game draws on every other line; sparks where an invader or the cannon is hit; the cannon's shots and the invaders' told apart. Sounds of Proteus's own for the invaders' step, the shot and the hits, each where it happens between left and right; the march in four notes, as the arcade had it; a hum that rises as the invaders get fewer and nearer. The controller shakes for all of them
Pac-Man 6e372f076fb9586aff416144f5cfe1cb (USA) the four ghosts in the red, pink, cyan and orange of the arcade, where the game's look alike, with eyes; blue while they can be eaten, flashing before that ends, and a pair of eyes when they were; all four in every frame, where the game draws one a frame. The maze as glowing blue outlines on black, the wafers as round dots, Pac-Man in yellow. Sparks where a ghost is eaten and where Pac-Man is caught. Sounds of Proteus's own for eating, the power pill, a ghost eaten and Pac-Man caught, each where it happens between left and right; the game's tune, its own notes in softer voices two octaves down; a siren under the chase that rises as the wafers get fewer, where the game is silent. The controller shakes for all of them
Combat 4c8832ed387bbafc055320c05205bc08 (Japan, USA) in all 27 variations: the two sides in red and blue, or the game's own colours made brighter; the score in the colours of its sides; ground under the tanks and a sky around the planes, in the game's own colour of the field; whiter clouds with light on them; shells white hot, with trails. Sparks where a tank or plane is hit, and a flash from the gun. Sounds of Proteus's own for each side's engine, which goes where its tank or plane goes, the shots and the hits, the shot of a tank told from the gun of a plane. The controller shakes for all of them
Warlords cbe5a166550a8129a5e6d374901dffad (USA) the four warlords, their shields and their castle walls in the gold, azure, emerald and violet of each, keeping the game's shades, or the walls of grey stone; the walls of a fallen warlord go grey. A fireball that burns from yellow to red and glows; a courtyard of flagstones, lit at each corner by its warlord's torches and with embers rising, where the game is black. Sparks where a brick breaks, fire and a flash where a warlord falls. Sounds of Proteus's own for a brick breaking, the fireball thrown and a warlord falling, each where it happens between left and right; a roar that follows the fireball, where the game is silent. The controller shakes for all of them
Missile Command 3a2e2d0c6892aa14544083dfb7762782 (USA) cyan cities on golden ground, red-hot trails with white warheads, a glowing counter-missile and glowing blasts, as the arcade had them; a night sky over a burning horizon where the game is black. Sparks where a missile is shot down, and fire and a red flash where a city is lost, both from the console's memory. Sounds of Proteus's own for the launch, a missile shot down, a missile on the ground and the buzz as a blast ends, each where it happens between left and right; a low rumble under the attack that grows as the missiles come nearer the ground. The controller shakes for all of them
Yars' Revenge c5930d0e8cdae3e037349bfa08e871be (USA) the shield and the neutral zone shown in every frame, where the game shows them in turns; the shield as embers and the neutral zone glowing; Yar's wings catching the light, a hot Destroyer Missile, a Swirl that spins through hot colours, a Zorlon Cannon that glows in flight; a nebula of stars where the game is black; sparks where a cell is eaten or shot and where Yar is hit, a blast and a flash when the Qotile is destroyed. Sounds of Proteus's own for the cells, the Swirl gathering itself and flying, Yar's death and the Qotile's destruction, each where it happens between left and right; the game's hum and beat played deeper. The controller shakes for all of them
Pitfall! 3e90cf23106f2e08b2781e41299de556 (USA) colours for every row of Harry, the logs, the fire, the cobra, the crocodiles, the scorpion, the wall and the treasures, which shine; leaves, bark, sand and earth in shades. Behind the trees the jungle further in, in three depths that move on from screen to screen, with the sun in the haze; rock in the tunnel, with daylight below the holes; water and tar that move. Sparks where Harry takes a treasure, is rolled over by a log, lands in the tunnel or loses a life. Sounds of Proteus's own for the jump, the fall, the landing, the logs and the loss of a life, where Harry is between left and right; the game's three tunes, note for note, as bells for a treasure, as a voice for Harry's call on the vine and as reeds for a life lost; birds, crickets and wind above ground and dripping water below. The controller shakes for all that happens to Harry
Ms. Pac-Man 87e79cd41ce136fd4f72cc6e2c161bee (USA) what Pac-Man gets, of the same parts: the ghosts in the arcade's colours with eyes, blue while they can be eaten, pale before that ends, a pair of eyes when they were, and all of them in every frame; each maze as glowing outlines on black in the colour the game gives it; round dots; Ms. Pac-Man in yellow; sparks where a ghost is eaten and where she is caught. Sounds of Proteus's own for eating and a ghost eaten, and for the power pill, which the game passes over; the game's tunes, its own notes in softer voices; sirens under the chase and while the ghosts can be eaten, where the game is silent. The controller shakes for all of them
Adventure 157bddb7192754a45372be196797f284 (USA) every room painted as large as the picture: walls of stone in the colour the game gives them, which throw shadows on a dark floor of slabs, and give off a little light. In the dark mazes the light of a lantern around the player where the game has a square of orange, and the walls hidden where it does not reach, which the effects for any game give away. The dragons in stronger colours with eyes, red while they bite, and dull when they are slain; steel for the sword, iron for the gates and the black key, red poles for the magnet. Every thing in every frame, where the game shows each in six frames of nine once three are in a room. Sparks and a flash when a dragon bites, eats or is slain, a glitter around the chalice. Sounds of Proteus's own for picking up and putting down, the bite, the dragon's death and the player's, each where it happens between left and right; the pitches of the game's end as chimes; wind around the castles, a drone in the dark mazes and a growl while a dragon is in the room, where the game is silent. The controller shakes for all of them
River Raid 393948436d1f4cc3192410bb918f9724 (USA) water with ripples and glints and banks of grass with a shore of sand, painted at the picture's size and moving with the river as the game's memory says it has; shallows and foam where the game has the shore, to the pixel. Helicopters, ships and jets in colours that stand out from the water, which the game's dark greens and blues do not; the fuel depots' letters lit; the jet lighter at the nose, with the light of its engine behind it; the gauge's needle red and blinking when the fuel is low. Sparks and a flash for whatever is hit, more for a bridge, and for the jet's wreck. Sounds of Proteus's own for the shot, the explosions, fuel taken on and the warning, each where it happens between left and right; an engine that follows the game's pitch and runs on under the sounds that silence the game's; the beat of a helicopter's rotor, which the game has not. The controller shakes for all of them
Asteroids dd7884b4f93cab423ac471aa1935e3df (USA) rocks of stone, lit from the upper left, with dents, tinted by their size and by the colour the game gave them; or the bright outlines of the arcade's screen. The rocks, the ship, its shots and the saucer in every frame, where the game draws the rocks in one and the rest in the next. Deep space where the game is black: a nebula and stars that drift. A flame behind the ship while it thrusts; sparks where a rock, the saucer or the ship is hit, as many as it was large; a flash when the ship is lost; sparks where the ship leaves for hyperspace and where it comes back. Sounds of Proteus's own for the shot, the thrust, the saucer and the explosions, which the game has one of and Proteus one for every size, each where it happens between left and right; the game's heartbeat, its own two notes, deeper, and beating on under the shots that cut it short in the game; a sound for hyperspace, where the game is silent. The controller shakes for all of them
Kaboom! 5428cdfada281c569c74c7308c7f2c26 (USA) bombs of blued steel with a fuse of rope and a spark that flickers, brass buckets of bright water, a crisper Mad Bomber in his stripes, the score in gold. A brick wall under the Bomber and a city's rooftops at night, with a moon, stars that twinkle and lit windows, in place of the game's grey and green. Fire and a flash where each bomb goes off, white hot to red; a splash and a shining bucket where one is caught; a blast where a bucket is lost, and the game's flashing colours as flickering firelight. Sounds of Proteus's own for the fuses, which hiss and crackle where the lowest bomb falls, a bomb caught, at the game's own pitch, each bomb going off and the bucket lost, each where it happens between left and right. The controller shakes for all of them
Frogger 081e2c114c9c20b61acf25fc95c71bf4 (USA) logs of wood, red turtles and the blue-green of those that dive, a green crocodile told from the logs by its shape, a pink lady frog, the snake, and a colour for every lane of cars, one of them no longer the frog's green; the frog bright and glowing, and the frogs come home. The river as water that drifts with each lane at half its speed, with glints and a wash at the ends of what floats; the road as asphalt with lane markings, lit ahead of every car by its headlamps; the safe strips as paving. A splash where the frog falls in, sparks and a flash where a car hits it, a burst of light where a frog comes home. Sounds of Proteus's own for the hop, the splash, the squash, the chime of a frog come home and the beeps as the time runs out, where the frog is between left and right; the game's tune, its own notes an octave down in warmer voices; the hum of the traffic and the rush of the river, louder as the frog is nearer. The controller shakes for all of them
Berzerk 136f75c4dd02c29283752b7e5799f978 (Japan, USA) the maze's walls electrified: glowing blue with a white core, current running along them and arcs that flare, the notches the game leaves in the left wall filled; or glowing and steady. The humanoid in the arcade's green, the robots in the colour the level gives them, brighter, with a red eye; Evil Otto a burning face that throbs; the humanoid's laser white and the robots' bolts red, both glowing, with trails; a floor of dark steel plates where the game is black. Sparks where a robot is destroyed; a flash, sparks, flaring walls and a humanoid flickering white and blue while he is electrocuted; a red flash as Otto comes in. Sounds of Proteus's own for the laser, the robots' bolts, a robot destroyed, a room coming on and the electrocution, which crackles for as long as it lasts, each where it happens between left and right; the hum of the walls and a throb that follows Otto, where the game is silent, each with an option of its own. The controller shakes for all of them
Pole Position a4ff39d513b993159911efe01ac12eba (USA) the arcade's colours: a red car with a yellow stripe, kerbs of red and white, other cars in brighter colours, clouds shaded underneath. A sky that deepens above and is hazy at the horizon, made from the game's own colour of it, with Mount Fuji and far mountains that turn with the road as the game's memory says the hills do; the game's hills as hills of grass and trees; grass beside the asphalt, in stripes that move with the kerbs' and haze in the distance. All of it found again in every frame from the picture, so that it keeps to the road on curves, and the title keeps its own colours. Sparks, fire and a flash of light on the circuit where the car crashes, and embers and firelight while it burns. Sounds of Proteus's own for the engine, which follows the game's pitch and runs on under the tyres, the tyres, the bumps off the road and the crash and its fire; the game's tunes, note for note, in brass and bass; the rush of a car overtaken, which the game has not. The controller shakes for all of them
Dig Dug 6dda84fb8e442ecf34241ac0d1d91d69 (USA) the earth painted at the picture's size in its bands of soil, with strata, grain and pebbles, darker and redder with depth, where the game has stripes; tunnels dug dark with crumbling edges, following the game's own to the pixel; a sky made from the game's blue; rocks as boulders of stone lit from above. Dig Dug in white and blue, red Pookas with yellow goggles, green Fygars with a white eye, only the goggles when they go through the earth; Fygar's fire burning and lighting the tunnel; the pump's hose shining; enemies paler and glowing as they swell. Sparks and a flash where a pumped enemy bursts, dust where a rock shakes loose and where it crashes, crumbs where Dig Dug digs, a red flash when he is caught. Sounds of Proteus's own for the hose, every stroke of the pump, the pop, Fygar's fire, a rock shaking loose and crashing, and Dig Dug caught, each where it happens between left and right; the game's tunes, its own notes an octave down in softer voices; the crunch of digging, which the game has not, with an option of its own. The controller shakes for all of them
Pitfall II: Lost Caverns 6d842c96d5a01967be9680080dd5be54 (USA) floors of worn stone, the rock under every ledge and the cavern walls in layered earth, found in every frame as the view scrolls when Harry falls; behind the black the rock of the caverns, darker under each ledge, with rock hanging from it, scrolling with the game; the underground river as water that moves and catches the light; the canopy, the jungle and the trunks above ground in greens and bark. Colours for every row of Harry, the frogs, the scorpions, the bats, the condor and Quickclaw; crosses that glow, gold that glints, electric eels that crackle and give off sparks. Sparks where Harry takes a treasure, is hurt, touches a cross, lands or splashes into the river. The DPC's three-voice music taken apart from the volume the game writes to the TIA on every line and played note for note with a round bass and two soft leads apart between left and right, and its drums as drums; dripping water and moving air in the caverns, the river where it is, wind and birds above ground. The controller shakes for a treasure, a hurt and a landing
Solaris e72eb8d4410152bdcb69e7fba327b420 (USA) every kind of screen told from the picture in every frame. Deep space of nebulae with stars that rush past, lit by the game's own colour for it: the warp a blue hyperspace of streaks that brightens, a danger zone crimson, a hit a flash of light; the gate at the warp's end glowing, and the flicker of arrival softened. On planets a sky from the game's colour, deeper above, a glowing horizon and ground lines of light over ground in the game's colour, also while it flashes in danger; the ringed planet in the sky and the planets that fly by in space glow. The map's grid glows over a dim galaxy, its signs as the game has them. Enemies in deeper, brighter colours, a torpedo of white light. Sparks and a burst of light where an enemy explodes and where the ship is hit. Sounds of Proteus's own for the torpedo, the explosions and the ship hit, and an engine's roar that follows the game's, each where it happens between left and right. The controller shakes for all of them
Jungle Hunt 2bb9f4686f7e08c5fcc69ec1a1c66fe7 (USA) in all four scenes, told by the game's memory. Behind the vines, the boulders and the cannibals the depth of the jungle: trunks in three depths, lianas, ferns and light falling through the canopy, moving with the trees as the explorer goes on; the canopy in leaves lit at its edge, branches of bark with moss, vines that are green and twist. The ground of the boulders and the cannibals as grass over earth with stones in it; that of the vines as grass and earth. Over the river a sky with clouds and the far bank; the water deeper and darker below, with light playing on it and shafts going down, the waves catching the light, the bed as lit stones, bubbles rising from the swimmer. The explorer in khaki with a white helmet, green crocodiles with a yellow eye and a glint of teeth, boulders of stone lit from above whose specks turn as they roll, cannibals with a skull and a leopard cloth, the captive with golden hair; the air gauge green, then amber, then red and pulsing. Leaves where a vine is caught, a glint of the knife, a burst and a flash where a crocodile is killed, a splash where the explorer dives, dust where a boulder lands, a red flash for a life lost, light when the captive is saved. Sounds of Proteus's own for the swing, the catch, the swimming above and under water, the knife, running out of air, the boulders landing, each where it happens between left and right; the game's tune, its own notes an octave down on a wooden flute, and the cannibals' tune on log drums; a crocodile killed, the dive, the air running low, a life lost and the rescue, where the game is silent; birds and crickets in the jungle and the hush of the river under water, with an option of their own. The controller shakes for all of them
H.E.R.O. fca4a5be1251927027f2c24774a02160 (USA) every screen of the mine told from the picture in every frame. Walls of rock in the colour the game gives each band, with strata that wander, grain and cracks, lit from above; lava that flows, bright where it is thin, and glows on the rock around it; a stream at the bottom that ripples in the game's colour for it. Behind the shafts dark rock in the level's colour, lit by the lanterns, the lava, the laser and the hero's helmet lamp. When the lights go out they fade, the rock goes dark but where the helmet lamp's cone falls, and the creatures glow; lava still burns. Creatures, the lantern, the dynamite and the miner in stronger colours, a laser of red light. The game's flashes as light of Proteus's: a blast of light, debris and dust where dynamite goes off, rubble along a wall blown up, a red light and a burst where the hero dies; sparks from the fuse and where a creature is shot, glass where a lantern goes out, a golden burst and fireworks when the miner is rescued and a glint for every unit of power counted. The power bar, the lives, the dynamite and the score as the game draws them, to the pixel. Sounds of Proteus's own for the propeller, which follows the game's pitch, the laser, the fuse, the blast, a creature shot, the hero's death, the power filling at a level's start, the power counted off as bells on the game's own note and the dynamite counted, each where it happens between left and right. The controller shakes for all of them

The TIA has two voices, and a game lets one sound cut another short. Proteus has a synthesizer of 32 voices (src/fx_synth.c), and a game's sound may take several of them: a thump below a click, a sweep over a burst of noise. A game module tells what the TIA's voices play from what the game writes to the audio registers, plays its own sound for it, and turns the game's voice down while it plays what the module knows. What it does not know is heard as the game plays it. Rumble sets how much the controller shakes, which it does whether the sounds are Proteus's or the game's.

A game is a file in src/games/ with a px_game: the MD5s, defaults for the options above, options of its own, a function that is given every frame between the finding of its objects and its drawing, with the console's memory, and one that hears every frame before its sound is mixed.

Every game is made the same way, from the same parts:

docs/GAME_MODULES.md the standard: how a game is added, the parts of its file, the rules it keeps, and what games have in common
docs/TOP_GAMES.md the games that get a module, from nineteen lists of the console's best, and what each will need
src/kit.h what modules share: colours, options, memory, what is known of an object, the game's voices
src/games/_template.c a module to begin from
tools/2600/ for studying a game: what it draws with what, what its voices play, what its memory holds
make lint-games holds every module to the standard, without a game

make test2600 checks all of it against Stella with a test program that test/rom2600.c writes, laid out like an early shooter. STELLA and STELLAPX name the two cores: Stella as its authors build it, and the fork's build. test/games2600.sh runs the same checks on games of your own.

Layout

Path Purpose
src/proteus_capture.h the capture interface between a core and Proteus: objects at every pixel, their colours, register writes, the voices
src/fx_video.c draws the picture again, with its effects, from what a system tells of a frame (px_source)
src/sys_tia.c Atari 2600: the TIA's capture as a px_source, and what Proteus holds Stella's options at
src/fx_track.c Atari 2600: the objects in a frame, and the same object over frames
src/fx_audio.c Atari 2600: the two voices, filtered, panned and in a room
src/fx_synth.c sounds of Proteus's own, of 32 voices
src/fx_pool.c the threads a picture is drawn by
src/fx_panel.c the options drawn on the picture
src/fx_game.c, src/games/ Atari 2600: the games Proteus knows in particular, found by MD5; games.h lists them
src/kit.h, src/kit.c Atari 2600: what game modules have in common
docs/ the standard for game modules, and the games that get one
src/engine.c song detection, choosing what plays, mixing, save state data (shared)
src/proteus.c the wrapper core: libretro API passthrough, option overrides, save states
src/dsp.c the DSP plugin: finds the running core and game inside RetroArch
src/options.c merges Proteus's core options with the wrapped core's, for every libretro option API
src/profile.c profile parser
src/music.c resampling mixer with crossfades and loops
src/decoders.c WAV / MP3 / Ogg decoders and libgme sources
src/usf_play.c N64 USF rips through lazyusf2 and psflib
src/twosf_play.c DS 2SF rips through vio2sf and psflib
src/ncsf_play.cpp DS NCSF rips through SSEQPlayer and psflib
src/vgm_play.c streamed music (DSP, BRSTM, BFSTM, ADX...) through vgmstream
studio/main.cpp Proteus Studio's window: the two song lists, replacements, Advanced tabs
studio/rom_session.cpp one open ROM: its emulator thread, song scans, finding how songs start, live ripping, song library
studio/game_db.cpp the game database (games.ini)
studio/snes_rom.cpp SNES ROM header, CRC32, and CPU address mapping
studio/reference.cpp reference songs: matching rips, finding song tables in the ROM, importing and downloading sets
studio/nsf_init.cpp a small 6502 that runs an .nsf's init and play routines: the RAM requests and routine calls that start its songs, and code patches that silence its music
studio/nes_tap.cpp taps on an NES game's sound routine: a stub in blank ROM, as cheat codes, reporting the game's requests
studio/song_notes.cpp a song's notes over time, for matching songs that memory cannot tell apart
studio/tas_runner.cpp TASVideos lookups and downloads, installing BizHawk, playing a movie in BizHawk with a RAM-saving Lua script
studio/movie_learner.cpp names the songs of a movie's moments and learns the song address from them
studio/folder_scan.cpp Scan folder: every ROM of a folder in turn, with a report
studio/zip_read.cpp, studio/http.cpp reading zip archives; HTTPS requests (RetroAchievements, Zophar's Domain, SNESmusic.org, TASVideos, GitHub)
studio/cli/proteus_cli.cpp proteus-cli: song tables, matching, scans (scan --profile exports one), TAS movies, folder scans and downloads without the window; nsftrace, nsfcalls, nsfpatch, nsfsurvey and nestap look into .nsf rips and design taps
studio/spc_rip.cpp turns a snes9x save state into an .spc file
studio/profile_export.cpp writes the profile and copies the music
studio/core_host.cpp minimal libretro frontend; runs up to four cores at once
studio/audio_out.cpp plays songs and game audio
deps/imgui/ Dear ImGui bundled library
test/ a fake game core and a headless frontend that checks the mixed audio and the options
test/rom2600.c, test/harness2600.c, test/run2600.sh an Atari 2600 test program, a headless frontend that hashes frames and checks the capture, and the checks of make test2600
test/lint_games.c the checks of make lint-games
tools/2600/ records a game's objects, sounds and memory, and finds what is what in them
tools/install-core.ps1 installs the plugin and wrapper cores into a RetroArch folder

License

Proteus Retune is licensed under the GNU General Public License v3 or later (GPL-3.0-or-later); see LICENSE. Releases up to 0.2.0 were LGPL-2.1-or-later. Bundled libraries in deps/ keep their own licenses:

Library License
deps/gme — libgme 0.6.5 LGPL-2.1-or-later (deps/gme/LICENSE); ext/emu2413 is MIT
deps/imgui — Dear ImGui 1.92.x MIT (deps/imgui/LICENSE.txt)
deps/lazyusf2 — lazyusf2 (modified Mupen64Plus) GPL-2.0-or-later (deps/lazyusf2/COPYING); its RSP interpreter is CC0, si/n64_cic_nus_6105.c BSD-2-Clause; see deps/lazyusf2/PROTEUS.md
deps/vio2sf — vio2sf (cut-down DeSmuME) GPL-2.0-or-later (deps/vio2sf/desmume/COPYING); see deps/vio2sf/PROTEUS.md
deps/sseqplayer — SSEQPlayer WTFPL-2.0 (deps/sseqplayer/LICENSE.TXT); see deps/sseqplayer/PROTEUS.md
deps/psflib — psflib MIT (deps/psflib/LICENSE)
deps/vgmstream — vgmstream r2117 ISC-style permissive license (deps/vgmstream/COPYING); see deps/vgmstream/PROTEUS.md
deps/libretro.h, deps/libretro_dspfilter.h MIT
deps/dr_wav.h, deps/dr_mp3.h public domain / MIT-0
deps/stb_vorbis.c public domain / MIT

Proteus Retune includes no games, ROMs, soundtracks or movies. Studio downloads, only when asked, SPC sets from Zophar's Domain and SNESmusic.org, input movies from TASVideos, and BizHawk (MIT) from its GitHub releases; they keep their own terms, and are kept in your %APPDATA%\ProteusStudio folder, not in this repository. Use ROMs you own.

Proteus Retune is not affiliated with or endorsed by Nintendo, Atari, Sony, Taito, Bandai Namco, Activision, Libretro/RetroArch, the Stella team, TASVideos, BizHawk, Zophar's Domain, SNESmusic.org or RetroAchievements. Game titles and characters are trademarks of their owners, named here only to say which games Proteus works with. Proteus contains no code, graphics, sound or music from any game or console.

Roadmap

  • Muting music by patching the game's play-song routine instead of muting channels

About

Swap game music in RetroArch while keeping sound effects: SNES, NES and N64 (Super Mario 64, Ocarina of Time). A libretro wrapper core, DSP plugin, and Proteus Studio for finding and mapping songs.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages