SIDin #14 — Inside Hunter's Moon (Martin Walker's sound-effects engine, reverse-engineered, 2015)

author Stefano Tognon (ice00), SIDin magazine
date 2015-01-25
article SIDin issue 14 (version 1.00, 2015-01-25), pp. 61–74: 'Inside Hunter's Moon' — sections Engine, Tables, Source Code (commented DASM-style listing with a PSID header), Conclusion. The engine analysed is Martin Walker's sound-effects player, not Matt Gray's music player
created 2026-08-30 · updated 2026-08-31

Tognon reverse-engineers the sound-effects engine of hunters-moon (Thalamus, 1987) — code, graphics and effects by Martin Walker, music by matt-gray — because "the hives seems to be true living": the most realistic game effects he knows turn out to come from a tiny table-driven engine that uses up to all three voices per effect, which is also, he suggests, why no music plays during the game. Rights stay with Walker.

Key claims#

  • Structure: InitEngine clears the 25 SID registers, sets volume $0F and zeroes the per-voice indexes; a sound is started by storing a table index into indexInTable (+0, +7, +14 for the three voices) — "That's all." playSound, called once per frame, runs setUpSound for X = 0, 7, 14: a non-zero index triggers outSidValue (load every register from the tables, then clear the index), then makeLoop and testAndMakeEffect keep the effect alive (sid-player-routine).
  • Thirteen tables of 32 entries, one column per effect index: tableAD, tableSR, tableWave (pulse width packed as XY$0YX0), tableFreqLo/Hi, tableControlReg (start), tableControlReg2 (written when the loop counter runs out), tableLoopValue, tableFreqLoStep/HiStep, tableFreqEffect (1 add, 2 subtract, 3 looped add, 4 looped subtract, 5 add while looping then subtract, 6 subtract then add), tableWaveStep (pulse step, bouncing between $08xx and $0Exx like Gray's player), tableFreqEffect2 (1 swap the frequency low and high bytes, 2 subtract the step and EOR #$DF, 3 subtract and EOR #$12, 4 add $D41B AND $0F — the noise of oscillator 3 — to the high byte) (randomization-and-probability).
  • Sixteen effect routines dispatched through a PSID "song" number 1–16 (lowTable/highTable): explosion, star cell, choose system, alternative choose, bell, short tick, long drill, plonk, fire, bell 2, bonus, launching, after bonus, stage start, middle, enemy explosion. Each just stores one to three indexes, e.g. soundBell = $16, $16, $17; soundFire = $12 on voice 1 only; soundPlonk = $07 and $04 on voices 2–3. "You can so have the user that fire the enemy and at the same time other sound effects being played."
  • Long effects: soundExplosion (indexes $0C/$0D/$0E) and soundStarCell set preLongEffect; the next frame longEffect = $32 (50 frames) during which voices 2–3 have their indexes cleared each frame, so nothing can interrupt the effect; flagExplosion/flagStarCell let the game request them asynchronously.
  • Fire ($12): AD $00, SR $30, control $11$10, loop 6, frequency $E0F0, effect2 = 1 — "a triangle sound that change frequency from two fixed value" by swapping the bytes each frame. Plonk: voice 2 index $07 with control $15 (triangle + ring modulation), SR $98, frequency $F400, high-byte step $0D, effect 5 (add for 8 frames, then subtract) — "a vibrato like sound, but is uses ring modulation"; voice 3 index $04, silent triangle $10, frequency $2011, step $01, effect 6 — the modulator, "opposite to the one used into the other voice" (ring-modulation-and-sync).
  • The listing is wrapped as a PSID v2 ("Hunter's Moon / Martin Walker / 1987 Thalamus", 16 songs, init initSongs, play playSound, code at $0900, "extracted from original TAP"), so every effect can be auditioned in a SID player (sid-format). Tognon marks oddities in the voice-state block ("[Missing!!]", "[Voice 1!!]") and a "missing store????" in addFreq (the low byte is written to the SID but not kept).
  • The game: "one of the best game ever", "128 levels", hard at first "but it has the right feeling".

Practical takeaways#

  • A complete SFX engine in about 250 lines: per-effect columns for ADSR, waveform, pulse, pitch, a loop length and two effect selectors, plus a frame routine. The two-control-register trick (start waveform, then a second one — usually gate off — after N frames) is the same idea as an instrument's gate-off frame (instrument-design).
  • Realism from register games rather than samples: byte-swapped frequencies, EOR scrambles of the high byte, oscillator-3 noise added to pitch, ring-modulated vibrato pairs.
  • Budget effects by voices: allow one-voice effects to overlap and reserve all three for the big ones — which may cost the in-game music (channel-interleaving).

Notable quotes#

"Before I reverse engineering the Martin code, I was sure it was a very complicated engine as the sound is the most realistic you can find into a game. But the engine is simple and the secret is just how the sid is manipulated in a convenient way :)"

"He uses even more SID voices for some effects … and maybe this is why music is not played during game play."

Relevance to the wiki#

Creates hunters-moon; a documented 1987 sound-effects engine next to the music drivers on sid-player-routine; ring-modulated and randomised effect recipes for ring-modulation-and-sync and randomization-and-probability; context for matt-gray's 1987 Thalamus credit (see also s-sidin15-serpent-demo-player, where Tognon finds leftovers of the Hunter's Moon tune in the Serpent Demo file).

To verify#

  • Tognon states the fire effect alternates between "0Eh and 0Fh"; the table gives $E0F0, so the swap alternates $E0F0 and $F0E0 — his figures look like the nibbles (unverified).
  • Whether Martin Walker's engine also drove the title-screen music is not discussed; the article says the music "is played using Matt Gray engine".

Pages touched#

hunters-moon · matt-gray · matt-gray-player · sid-player-routine · ring-modulation-and-sync · randomization-and-probability · instrument-design · channel-interleaving · sid-format · sidin · sound-effects

source file wiki/summaries/s-sidin14-hunters-moon.md · 1 unverified · graph