Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CDJ-900NXS firmware patcher
Builds a new C900NXS.UPD from the official CDJ-900NXS firmware 1.31 with
the mods you choose, for the player's own USB update.
python cdj900nxs_patcher.py C900NXS.UPD # choose in a list
python cdj900nxs_patcher.py C900NXS.UPD --mods cuecolours,hotcuekeys
python cdj900nxs_patcher.py C900NXS.UPD --stock # the original, to go back
python cdj900nxs_patcher.py --list
In the list: arrow keys move, space ticks or unticks, a ticks all
or none, enter builds, q quits. Ticking a mod ticks what it needs;
unticking one unticks what needs it (utility needs code, hotcuekeys
needs cuecolours). A mod with known faults starts unticked.
Before anything is built the patcher shows a disclaimer that must be
accepted by typing yes (or with --accept, where no one can type): the
mods and the patcher were developed with Claude Code, Anthropic's AI coding
assistant, and are used at your own risk. Terminals that cannot pass single
keys (Git Bash's mintty, a pipe) get a numbered list instead. The result goes
to out/<date>-<mods>/C900NXS.UPD with a report.txt of every check.
What it guarantees
- Only the original file is accepted: SHA-256
e96bca7d1ac983985992a8e5fa7813e1ebf04bef514e0c6cfd0a8375f667f7f9, and the 1.31 application inside it is checked too. - Only the main application is replaced. The boot loader and recovery loader (MAIN's records below flash 0x40000), MAIN's S0 header and S7 entry records, and the DRIV and PANL sections are copied from the original byte for byte. Before anything is written the finished file is read back and checked: every section CRC and S-record checksum; DRIV and PANL equal to the original; MAIN's header equal but for its version label, application-only mode kept; every boot loader and recovery record and byte equal; no record past 0x7E0000; the packed application's checksum; and the application, unpacked the way the boot loader does it, equal to the patched one.
- Labelled 1.32, so that the player's updater does not skip the update as
the version it already has. The application still reports 1.31 (as
arnoldasr's builds do).
--stockgives the original firmware with only that label changed: three bytes differ from the official file (the digit and the section CRC), exactly as arnoldasr's back-to-stock file, which installed on his test player.
Checked in the emulator: both the --stock file and one with every mod were
written into an emulated flash and booted through Pioneer's own boot loader,
which unpacked and started them.
Mods
From the emulator checkout ../CDJ900NXSVirtual (--repo for another place):
mods/patch_cdj900nxs.py and the mods next to it.
| mod | what it does |
|---|---|
code |
arnoldasr: BPM with two decimals, two-line phase meter, RGB waveform |
utility |
arnoldasr: UTILITY > PHASE METER switch (needs code) |
overview |
arnoldasr: overview waveform colour gradient |
beatjump |
TRACK SEARCH jumps 1/2/4/8 beats, UTILITY > BEAT JUMP (needs hotcuekeys), see below |
cuecolours |
memory cues in their rekordbox colours, hot cues shown |
hotcuekeys |
hot cues A-C on the BEAT DIVIDE keys (needs cuecolours), see below |
ledsaver |
UTILITY > LED ANIMATION: while the screen saver dims the display, the button LEDs and the jog's rings play a loop |
credit |
the boot screen says "Pionaarr Mods by Givou" where it said "Ver 1.31" (ticked at the start, can be unticked) |
hotcuekeys: UTILITY > HOT CUE KEYS ON; then QUANTIZE pressed briefly
switches the hot key mode (HOT KEYS box beside QUANTIZE), held it is
QUANTIZE. In the mode the BEAT DIVIDE keys 3/4, 1/3, 1/2 are hot cues A-C
(1/4 and 1/8 do nothing and stay dark: the player has three hot cue buffers,
one for each):
- press: jump to the hot cue and play (from pause too);
- hold 0.5 s or longer, then let go: back to the hot cue, standing (gate);
- an empty key held 0.8 s while paused: a hot cue there;
- DELETE held, a key pressed: its hot cue deleted (DELETE alone is DELETE);
- LEDs: off without a hot cue, dim with one, two bright blinks when pressed.
Hot cues set or deleted are written to the USB stick (the track's rekordbox analysis files, as MEMORY and DELETE keep memory cues), so they are there after the next load too. As with MEMORY, the player takes this only once the track has settled (a few seconds after loading). Hot cues A-C start at once: once a track is loaded and the deck stands at its CUE point for a second (in hot key mode), they are loaded into the player's three hot cue buffers, silently, and the deck goes back to its CUE point. PLAY or CUE pressed meanwhile wait for it (PLAY is played after). A hot cue set later loads into its own buffer on its first press (about a second). A hot cue played from a buffer leaves the CUE point where it is; one recalled without a buffer moves it, as CALL does.
ledsaver: UTILITY > LED ANIMATION, ON from the first start (set it to OFF
to switch it off; the player keeps the choice). When the
player's own screen saver dims the display (5 minutes without a track, or
100 minutes paused), the BEAT DIVIDE keys fade in a wave down and back up,
SYNC / MASTER and MASTER TEMPO / DISC EJECT fade in and out, CUE, PLAY, REV,
SLIP, the SLIP LOOP bar and RELOOP/EXIT light one after another, and the
jog's three rings light in turn from the inside out and back in. Any key ends
it, as it ends the screen saver.
beatjump: UTILITY > BEAT JUMP (where SCREEN SAVER was) sets 1, 2, 4 or 8
beats (OFF: TRACK SEARCH as before); TRACK SEARCH back and forward then jump
that many beats along the track's beat grid, keeping the position within the
beat. While playing, the jump is loaded into a buffer of the player's own
that only beat jumps use (A-C keep theirs): there is a short silence while it loads, but the
deck comes back in phase, as if it had played on through it (the load time is
measured on every jump and allowed for), and the CUE point stays. Paused, it
is a CALL (the CUE point moves with it). A press while a jump or hot cue is
still loading is ignored.
arnoldasr's mods need his repository checked out in
../CDJ900NXSVirtual/mods/cdj900nxs/upstream (it has no licence, so it is
not copied here); without it they are greyed out.
Risk
Nothing here talks to a player; you copy the file to a FAT32 USB stick and run
the update yourself. Our mods were developed with Claude Code in an emulator.
An earlier beatjump jumped off the grid on a player and, after a few quick
jumps, reported a corrupted file and needed a restart; it has been rebuilt on
the hot cue engine (no overlapping loads), which has not run on a player yet,
nor has the hot cue engine. A jump while a loop plays ends the loop. cuecolours and earlier versions of hotcuekeys
ran on a player. Recovery from an
application that crashes at start-up has not been tested by anyone. Keep the
--stock file at hand.
Tests
CDJ900NXS_UPD=/path/to/C900NXS.UPD python -m pytest test_patcher.py