DARKER Research archive

Audio extraction: first playable exports

2026-09-18. Open the listening gallery.

For later work, see the hardware and Roland investigation, including custom instruments, missing percussion, independent loop timing and hand-corrected FLAC references.

Six Roland SCC-1 arrangements now export as standard MIDI, with Ogg Vorbis listening previews. The gallery offers both plus source event/loop metadata. These are the six music groups' SCC-1 variants, not 30 distinct songs. Their original song titles remain unknown. Scene assignments and chained briefing selections are now listed in the scene and music catalogue. Group 1 is startup and menu music (see below).

The Ogg files are now rendered by FluidSynth with FluidR3 GM, not recordings of Darker or emulation of the SCC-1's exact instrument set. Their purpose is to hear the recovered arrangements. The preview provenance records the soundfont hash, sample rate and encoding. Original hardware timbre, game volume/fades, interrupt quantisation and repeated playback are not claimed.

Correction: DC saturation in the first preview render

Listening to the startup preview showed that it deteriorated around 11 seconds and provided an Audacity screenshot showing its left channel driven up to full scale. Decoded Ogg measurements confirmed this. By the latter part of the old render, the output was almost entirely positive full-scale DC. Smaller drifting offsets were also present in several other tracks.

Controlled rerenders of the same MIDI and soundfont reproduced the problem with TiMidity even with reverb and chorus disabled. FluidSynth did not reproduce the saturation. This isolates a preview-synthesis-path problem; the precise TiMidity failure is not yet diagnosed. The music decoder was not changed to reinterpret volume as pitch or vice versa: the original driver's command 95 emits MIDI pitch bend and command 96 emits controller 7 (volume), as already checked against its instruction output.

All six listening copies were regenerated with FluidSynth and encoded directly to Ogg Vorbis, with no DC blocker or other corrective filtering. MIDI and source-event metadata remain unchanged. The synthesis settings and absence of filtering are recorded in variants/previews.json.

The individual variants/group-N-scc1-check.json reports contain both source PCM and final Ogg measurements, per channel in five-second windows. Checks guard against large DC offsets and clipping; small residual synthesis offsets are retained. These checks detect this failure class; they do not validate musical interpretation or original hardware timbre. The gallery includes a content-hash query on each audio URL to avoid stale cached previews after regeneration.

Other hardware variants

All thirty native sequences and their five drivers now have a dedicated export and comparison page, including source command inventories. See hardware differences and conversion limits. Only the SCC-1 versions currently have verified standard MIDI conversions. The other four hardware variants now have provisional MIDI/GM auditions, selectable in the gallery; their hardware-specific command mappings remain unverified.

What the executable establishes

The game selects driver resource 33 + driver_index at 9C66–9C74. Music loader 0AAE–0AC1 selects 38 + 5*music_group + driver_index, appends it to the loaded driver and invokes driver API function 4 with song number 1 (0AC4–0AC7). Thus the five-way grouping is established by code, not merely similar headers.

Group SCC-1 resource Sequence tracks Initial BPM Division Loop-end tick
1 00/39 15 98 96 12,672
2 00/44 15 90 96 4,704
3 00/49 9 92 96 4,704
4 00/54 13 90 96 4,704
5 00/59 11 90 96 4,704
6 00/64 12 100 96 6,144

Within each arrangement, every track reaches its loop at the same tick. The MIDI exports contain one initial traversal of each track, then added all-notes-off messages so a finite audition can end cleanly. Source loop targets are preserved in JSON: repetition may start after introductory setup, not at the file beginning. No scene names have been invented for these tracks.

Startup music identification

The opening music is group 0 in the engine's zero-based selector: group 1 in our gallery, SCC-1 resource 00/39 (Sound Blaster variant 00/38). Startup 9CBD–9CBF calls D8D6 with AL=1, selecting stored record 1 from resource 04/15. Its scene script contains the music command 40 00; opcode 40 routes through C067 to 0A99, selecting music group zero. The return-to-menu path independently does XOR AL,AL; CALL 0A99 at 3F47–3F49. The original song title remains unknown; “Startup music” is a functional label.

Container and sequence format

Offsets here are within resource 00/34, the SCC-1 driver, unless stated otherwise. Its public entry at 0000 dispatches by AH through the table at 026A. Function 3 services the player at 02A3; function 4 selects the song.

Music resource layout recovered from 03C0–046E:

The driver keeps 16 track states of 23 bytes each at 008A. The first word is the stream cursor; +2/+4 is the countdown, +6 the loop cursor, +8 the selected channel, +9 the last note, and +A the activity/mode byte.

Event SCC-1 handler meaning
00–7F Note-on; event byte is note, following byte is velocity
80–8F Select channel; no MIDI event by itself
90 nn Note-off represented as note-on nn with zero velocity
91 Stop track and silence channel
92 pp Program change
93 tt Change tempo
94 No-op in this driver
95 bb Pitch bend, low seven bits zero, high seven bits bb
96 vv Channel volume, scaled by master volume
97 xx Update driver track field +14; retained in command metadata
98 Return to saved loop cursor
99 Release last note on channels 0–11; channels 12–15 use the driver's digital-voice stop branch
9A Park stream at the driver's sentinel delay
9B pp Pan controller
9C Save loop cursor at the following delta
9D cc vv MIDI controller/value pair
FF No event; proceed to the next delta

The extracted songs exercise channel selection, notes, explicit/last-note release, instrument changes, volume, pan, pitch bend, controller commands and loops. The less common terminal/tempo/park cases above are identified statically; they are not all exercised by these six arrangements.

0668 computes sequence progress from the timer divisor and the two tempo bytes: the constant 0444:6390 is 71,590,800 (1,193,180 × 60). This establishes the musical division/tempo interpretation. Conversion to MIDI retains musical tick time; it does not reproduce the driver's quantised interrupt delivery. The game sets the driver's timer-divisor parameter to 5D24 at 9CA4–9CA9.

Original-code verification

verify_audio.py executes each exported event through 031A and each preceding delta through 05FE, in the original SCC-1 driver. It intercepts MIDI output at 0796/079F before hardware polling, retaining full status bytes instead of the hardware path's running-status suppression. Driver state persists across events in a track, and master volume is set to unity.

20,545 event commands and 20,545 delta decodes match, including stream cursor positions and first-loop destinations, across all 75 tracks. See scc1-verification.json.

The check does not run hardware initialization, the full periodic scheduler, MIDI synthesis or the complete game. The driver has digital-voice branches for some commands; those are not converted into fabricated MIDI notes or sample assets. Exact source command records remain available for subsequent work.

Sound effects are a separate investigation

The main executable itself contains a direct FM register-write path: 1185 sends a register index to port 0388, and the following code sends its value to 0389, using PIT reads for delays. 113E–1181 programs operator and channel registers. 0EDB onward maintains effect voice state, and 0E82 has a special interaction with the Sound Blaster music driver's internal tables.

This is evidence for a procedural FM effects path, not a bank of ordinary WAV files waiting to be renamed. The music drivers also contain digital-audio support; that does not by itself establish sample payloads used by this game. The next step is to recover the effect definitions and their evolving register writes, then render them through an appropriate OPL implementation with verified timing. A subsequent effects extraction pass now exports the embedded FM definitions and playable isolated auditions. Full live modulation remains separate from those previews.

Reproduction

python3 tools/extract_audio.py
PYTHONPATH=/tmp/darker-python python3 tools/verify_audio.py
python3 tools/render_audio_previews.py

Extraction uses Python's standard library. Verification requires Unicorn. Preview rendering requires libfluidsynth.so.3, ffmpeg and the locally installed FluidR3 GM soundfont; it does not bundle the soundfont with the extracted assets.

Earlier Sound Images investigation

2026-09-18. We examined the Aminet Sound Images EaglePlayer package. The downloaded LHA contains an Amiga executable replayer and ripper, plus readmes; no source code. Its readme says version 2 adds Sound Images Generation 2 support and exposes sample-saving through EaglePlayer 2. This is useful prior work, but not evidence that it directly accepts Darker's DOS resource format. “PC relative” in this Amiga context means program-counter-relative, not PC/DOS.

The ripper contains the attribution Tony 'Tiny' Williams, adapted by Wanted Team. Darker's resources 00/39–41, 44–46, 49–51, 54–56, 59–61 and 64–66 contain Tiny at byte offset 4. The sound drivers already explicitly identify Tony Williams / Sound Images Generation 2 v1.11x. These are consistent provenance clues, not proof of binary compatibility between Amiga and DOS songs.

Resources 00/38–67 show six repeating groups of five related stream variants, consistent with the five extracted hardware drivers. Headers start with 01 and a little-endian word, followed by command-like bytes. Neither raw PCM nor standard MIDI/WAV framing is established. The exact length/table semantics, timing, command set and instrument/sample banks still need tracing through the DOS drivers. Do not rename these resources .mid or .wav and expect playback.

All thirty candidate streams and five drivers have already been losslessly extracted into analysis/resources/. At that stage there was no playable audio export. The next useful step is tracing one driver's event decoder, then separating sequence conversion from sample-bank extraction. Emulator recording is another route to a listening copy, but would not by itself explain the format.