ROM retuning — patching a tracker's pitch table

Overwriting the block of precomputed pitch values inside a tracker's ROM, so that every note in the sequencer plays at a frequency you chose. It is how alternative-tunings are done on the game-boy, and it is also the repair for an underclocked machine. The whole job is: find the table, compute a new one, paste, flash.

Why it works#

A game-boy-apu channel is pitched by an 11-bit period value v, where the pulse frequency is 131072 ÷ (2048 − v) Hz. Nothing in the chip knows about notes. lsdj and nanoloop each carry a table of those integers, one per playable note, and index it from the note column — so the table alone decides what "C-4" means. Replace it and the sequencer, the instruments, the tables and the effect commands all carry on unchanged, playing something else (sources: s-little-scale-lsdj-tuning-tables, s-little-scale-nanoloop-18-tet).

The arithmetic#

Forward (frequency → register value), and back again to see what you actually got — little-scale's own spreadsheet columns (source: s-little-scale-nanoloop-18-tet):

Data      = 2048 - (131072 / Frequency)        round to an integer
Resultant = 131072 / (2048 - Data)             what the chip will really play

Write each value little-endian, low byte first: 44 → 2C 00, 156 → 9C 00, 262 → 06 01.

Building the frequency column:

Mapping fewer than 12 degrees onto 12 keys#

A pentatonic ROM still has twelve keys per octave, so some of them must repeat. little-scale's hirajoshi sheet pairs each chromatic key with a scale degree explicitly — degrees 0,0,1,1,1,2,2,3,3,3,4,4 across the octave, a 2-3-2-3-2 spread that keeps the tonic on the same key every octave (source: s-little-scale-koto-tuning).

How to do it#

LSDj — by hand#

Offsets verified on 3.8.9 only (source: s-little-scale-lsdj-tuning-tables):

whatoffsetsizenotes
GB / GBC / GBA pitch table$6D3A (27,962)216 bytes = 108 × 2starts with the bytes 2C 00 9C 00 06 01
Super Game Boy pitch table$6E12 (28,178)216 bytesimmediately after the first, recomputed for the SGB1's ~2.4 % fast clock
  1. Open the ROM in a hex editor in overwrite mode (little-scale uses Hex Fiend on OS X). Do not insert — the ROM must stay 1,048,576 bytes.
  2. Find the table: "starts just after location $6D30 with the bytes 2C 00 9C 00 06 01. Select 216 bytes starting with 2C and 00" (source: s-little-scale-underclocking-and-retuning).
  3. Paste your 108 little-endian values over it.
  4. Patch the second block too. KiGB reads only the SGB table "regardless of emulator settings", so a ROM patched in one place will test wrong there and play wrong under a Super Game Boy (source: s-little-scale-lsdj-tuning-tables).
  5. Save, flash, play.

LSDj — with lsdj_tune#

abrasive's Perl script does all of the above from the command line and, uniquely, rewrites the note names as well, so the display matches the tuning. Built for LSDJ 3.9.9 (source: s-little-scale-abrasive-lsdj-tune):

lsdj_tune --et 24 --base A5 440 --rom lsdj.gb --out lsdj_et24.gb
lsdj_tune --cstep 78 --base 0 70 --rom lsdj.gb --out lsdj_alpha.gb      # Wendy Carlos alpha
lsdj_tune --ratio 1,256/243,9/8,32/27,81/64,4/3,729/512,1024/729,3/2,128/81,27/16,16/9,243/128,2 \
          --names D,Eb,E,F,F#,G,G#,Ab,A,Bb,B,C,C# --base 0 73.42 --rom lsdj.gb --out lsdj_pyth.gb

Modes: --et n, --cents, --cstep, --ratio; all 108 notes may also be given explicitly. Its stated limitation is that the base-frequency option "won't take custom note names, and sequences always start on the base note".

Nanoloop#

For 1.3d (nl13d.gb, 32,768 bytes): the pitch table is 144 bytes at $730A (29,450), and its stock contents are the same 12-TET-from-C2 series as LSDj's (source: s-little-scale-nanoloop-18-tet). Same procedure, same formula.

Changing the clock instead — underclocking a DMG#

Swapping the DMG's crystal moves pitch and tempo together by one ratio, which is the only way to get a sub-octave Game Boy that still runs a stock ROM (source: s-little-scale-underclocking-and-retuning; the mod itself documented by Gieskes):

  • Stock crystal: 4.194304 MHz.
  • 2.097152 MHz — exactly half. One octave down, everything still in 12-TET, no patch needed. nitro2k01 called it "the elusive 2.097152mhz crystal oscillator" in June 2009; it is the harder part to buy.
  • 2.000000 MHz — the one shops actually stock. The ratio is 0.4768, an octave and 82 cents, so the machine lands nearly a semitone below the octave: "some disgustingly out of tune B or something similar".
  • The fix, from Tom Gilmore (10k): build the pitch table for twice the fitted crystal — 4.000000 MHz for a 2 MHz machine — and paste it in. The ROM is then an exact octave below written pitch and in tune with everything else. little-scale's 108-value replacement table is printed in full in raw/little-scale/retuning-underclocked-game-boy.txt; decoded against 4 MHz its first octave is 65.41 · 69.29 · 73.40 · 77.79 · 82.40 · 87.29 · 92.52 · 97.96 · 103.82 · 110.04 · 116.50 · 123.52 Hz.
  • Physically: the replacement crystal is taller than the original, so it is "bent over and put on its side, with some tape that insulates it from the rest of the PCB".
  • Overclocking is the same problem mirrored. He had built an 8 MHz DMG a year earlier — "almost twice the speed, almost twice the pitch" — and 8.000000 ÷ 4.194304 = 1.9073 is an octave minus 82 cents, the same error as the 2 MHz crystal in the other direction. Asked in 2009 whether his replacement table would also serve at 8 MHz he said "in theory… because I haven't actually tried it out with an overclocked GB"; by the rule above the table for an 8 MHz machine should be computed for 4 MHz, half the fitted crystal (sources: s-little-scale-overclocked-game-boy, s-little-scale-underclocking-and-retuning).

An underclocked machine still syncs with a stock one over the link port (sync): make the normal Game Boy the slave, or run the underclocked one as master at double tempo (254 against 127) (sources: s-little-scale-underclocking-and-retuning, s-chipmusic-lsdj-faq).

Tips & pitfalls#

  • Offsets are version-specific. A commenter who applied the 3.8.9 table to 4.0.5 got a cartridge that "would not boot up" (source: s-little-scale-underclocking-and-retuning). Always confirm the signature bytes 2C 00 9C 00 06 01 are at the address before overwriting, and keep the original ROM.
  • Overwrite, never insert. Any length change breaks the ROM.
  • Two tables, not one, on LSDj — and KiGB reads the wrong one.
  • Test on hardware, or in an emulator that reads the table you patched. Emulator and hardware disagree here more than usual.
  • Note names will lie after a hand patch; only lsdj_tune --names fixes the display.
  • The bottom octave and a half is lost below 64 Hz, and the top octave is quantised into unisons — plan the tonic so the useful range sits in the middle (game-boy-apu).
  • Retuning and reclocking are independent and compose: an underclocked machine can also be microtuned, by computing the table for both the new clock and the new scale.

alternative-tunings · game-boy-apu · lsdj · nanoloop · game-boy · sync · semitone-math · scales-and-modes · harmonic-series · abrasive · little-scale · nitro2k01

Sources#

s-little-scale-lsdj-tuning-tables · s-little-scale-underclocking-and-retuning · s-little-scale-koto-tuning · s-little-scale-nanoloop-18-tet · s-little-scale-abrasive-lsdj-tune · s-little-scale-overclocked-game-boy · s-chipmusic-lsdj-faq

source file wiki/techniques/rom-retuning.md · graph