Skip to content

SampledSound — .instr and .ss instruments

The instruments SMUS scores reference are Aegis Sonix “SampledSound” files (Mark Riley, 1987) — the native authoring format of Aegis Sonix, not Deluxe Music Construction Set. War in Middle Earth embeds the SSonix Music Driver v2.0b, which reads them and drives the Amiga’s Paula audio hardware directly.

32 .instr files and 4 .ss files ship with the game, in three roles:

  • 26 music instruments — referenced by name from SMUS INS1 chunks.
  • 3 sound effects — IFF 8SVX, triggered by game logic rather than by a score: Sword (3,348 B), Magic (7,442 B), Whoosh (2,014 B). Their 8SVX annotation records that they were sampled on SunRize “Perfect Sound” hardware.
  • 1 synthesis instrument — Himalayas22.instr, whose magic is "Synthesis" rather than "SampledSound", routing it to the driver’s tone/synth voice dispatch instead of the sampled-sound one.

.ss files hold five concatenated octave copies, and the current decoder reads them as one flat buffer. It has no octave handling at all — a known open bug, written up in docs/wime/amiga/smus-decoder-issues.md. Anything derived from .ss sample lengths or offsets should be treated as suspect until it is fixed.

Variant 1 — external reference (128 bytes). A magic-identified stub that names an external .ss file for its sample data. The override fields at +0x68 map onto the .ss header’s own envelope fields at +0x06–+0x1E only; oneShotLen, repeatLen, loOctave and hiOctave are intrinsic to the sample and are never overridden.

Variant 2 — synthesis instrument (502 bytes). No external sample: the waveform is generated at runtime by the driver’s oscillator engine from a 434-byte data block of four sections — a 128-byte source waveshaper, a 128-byte shaping curve, a 128-byte transfer function, and 50 bytes of synthesis parameters.

Variant 3 — IFF 8SVX (variable, > 502 bytes). Ordinary 8SVX sound effects, played outside the music system entirely.

A 62-byte header followed by signed 8-bit PCM (two’s complement, the same convention as an 8SVX BODY chunk), starting at +0x3E.

+0x00 u16 oneShotLen length of one copy at the lowest octave, in samples
+0x02 u16 repeatLen loop portion, in samples
+0x04 u8 loOctave lowest octave present (3 in all four files)
+0x05 u8 hiOctave highest octave present (7 in all four files)
+0x06 u16 volume output level, 0–255
+0x08 u16 attack envelope attack rate
+0x0A u16 decay envelope decay rate
+0x0C u16 sustain envelope sustain level
+0x0E u16 release envelope release rate
+0x10 u16 param1 envelope stage value
+0x12 u16 param2 envelope stage value
+0x14 u16 param3 envelope stage value
+0x16 u16 tailLen envelope tail length, in sample-rate ticks
+0x18 u16 param4
+0x1A u16 param5
+0x1C u16 param6
+0x1E u16 percmode 0 = sustained, 1 = one-shot
+0x20 30 reserved zeros

percmode is the field that separates the pitched instruments from the drums: Piano is 0 (sustained), BassDrum and SnareDrum are 1 (one-shot).

The four shipped samples, all at the 8,363 Hz base rate:

File Bytes Payload oneShotLen Duration at octave 3
Piano.ss 39,746 39,684 160 19.2 s across 5 octaves
BassDrum.ss 3,286 3,224 13 1.54 s across 5 octaves
SnareDrum.ss 19,406 19,344 78 9.35 s across 5 octaves
Trumpet.ss 22,382 22,320 90 10.7 s across 5 octaves

The driver uses 8,363 Hz as the C-3 base DMA rate — NTSC period 428, 3546895 / 428. Per-semitone pitch within an octave slice scales from that rate through the note-period table.

The driver does not use an instrument’s sampleParam as a direct DMA rate. Pitch is derived in three steps: a base period from the note number, an octave shift applied as a finetune offset, and a final AUDxPER computation — which is what selects the right octave copy out of the concatenated payload, and why the missing octave handling in the decoder matters.

docs/formats/sampled-sound.md in the main repository (not part of this site) — 600+ lines covering the synthesis engine’s per-tick voice handler, the 26-byte voice state block, the transfer-table byte-to-u16 mapping, the LED low-pass filter, and every sampleParam value observed. The open octave bug is written up in docs/wime/amiga/smus-decoder-issues.md.