74 lines
4.3 KiB
Markdown
74 lines
4.3 KiB
Markdown
# Music and sound
|
||
|
||
Sound is the least explored part of the game. This page separates what is verified from what is
|
||
only a guess. Custom music or sound effects are **not supported yet** by any LlamaMod tool.
|
||
|
||
## Music
|
||
|
||
| Fact | Status |
|
||
|---|---|
|
||
| Music tracks are files `music/<NAME>.asf` on the CD (33 files) | certain |
|
||
| A level does not reference music files directly: **environment zones** carry a music id, and the start zone's id plays when the level begins | certain |
|
||
| Music ids map to names through a table in `groove.exe` at 0x578960 (20 bytes per entry, name pointer at +8), played by `FUN_00546b70`; id 0 stops the music | certain |
|
||
| ASF here is Argonaut's own format (not Microsoft ASF): 4-bit ADPCM, 44.1 kHz stereo, 17-byte blocks, decoded by `asfcodec.adl` in the game folder | certain (decoder reimplemented) |
|
||
| A second zone field (u16 at +0x56) is probably the ambience setting | likely |
|
||
|
||
The id table, as used by the editor's zone inspector
|
||
([`EnvMath.MUSIC`](../../src/main/java/com/eliasmueller/llamamod/editor/tools/environment/EnvMath.java)):
|
||
|
||
| Id | Track | Id | Track | Id | Track | Id | Track |
|
||
|---|---|---|---|---|---|---|---|
|
||
| 0 | (stop) | 10 | GAMEOVER | 20 | SNKJUNG | 30 | TUNE1 |
|
||
| 1 | VILLAGE | 11 | TALLY | 21 | FROG | 31 | CHACHA |
|
||
| 2 | JUNGLE1 | 12 | TURRACE | 22 | KRONK | 32 | JJUNGLE2 |
|
||
| 3 | RIVER | 13 | PACHASNK | 23 | KIDLLAMA | 33 | TUNE9 |
|
||
| 4 | JUNGLE2 | 14 | MOUNT2 | 24 | TUNE8 | 34 | TUNE6 |
|
||
| 5 | MOUNTAIN | 15 | BALLOON | 25 | ROLLER | 35 | VICTORY |
|
||
| 6 | CITY | 16 | JUNGSPID | 26 | BUNNY | 36 | PUZZLE2 |
|
||
| 7 | CATACOMB | 17 | JAGCHASE | 27 | BLOCK | 37 | PLATFORM |
|
||
| 8 | LAB | 18 | RIVER | 28 | TUNE5 | 38 | (none) |
|
||
| 9 | TITLE | 19 | RIVRACE | 29 | CITYPUZZ | 39 | ENDGAME |
|
||
|
||
Four names (GAMEOVER, TALLY, PUZZLE2, PLATFORM) have no `.asf` file on the German CD; what the
|
||
game plays for them (probably nothing) was not checked.
|
||
|
||
**Changing the music of a level** works today: pick another id for the start zone (or any zone)
|
||
in the editor's *Environment* panel ([manual: Environment](../manual/12-environment.md),
|
||
[tutorial: Edit an original level](../manual/tutorial-original-level.md)).
|
||
|
||
**Listening to the tracks:** [`tools/asf2wav.py`](../../tools/asf2wav.py) `in.asf out.wav`
|
||
decodes a track exactly like the game's codec (filter 0: `s = s1 + (n << shift)`, filter 1:
|
||
`s = 2·s1 − s2 + (n << shift)`, 16-bit wrap-around instead of clipping – FFmpeg's decoder clips and
|
||
drifts).
|
||
|
||
**New music – open:** there is no encoder yet. Writing one (the inverse of `asf2wav.py`) and
|
||
replacing a track file through a mod would be the natural next step; the header fields after the
|
||
block count (`rate`, `flags` with bit 1 = stereo) are read by the decoder, the others are *unknown*.
|
||
|
||
## Sound effects
|
||
|
||
| Fact | Status |
|
||
|---|---|
|
||
| Each level has its own sample bank, chunk **SMPC**: `u32 n`, n × `{u32 "cvg " tag, u32 length, data}` | certain ([`SoundMerge.java`](../../src/main/java/com/eliasmueller/llamamod/format/stpcmerge/SoundMerge.java)) |
|
||
| Strats play samples by index (`soundPlay(sound:N)`, opcodes 0xd5 / 0x99 / 0x131 play, stop, is-playing); at most **128** samples per level, ids with bit 0x80 are the front-end sounds | certain |
|
||
| The samples are PlayStation-style VAG ADPCM, decoded by `Vagcodec.adl` | likely (tag and codec name; the sample header was not decoded) |
|
||
| **AMPC** holds ambient sound data (`ambi` / `VABp` blocks) | likely, not decoded |
|
||
| `FESOUND.WAD` is the front-end sound bank (not a chunk file) | likely |
|
||
|
||
Samples can be **moved between levels**: the editor's cross-world import and the arena copy the
|
||
samples an imported object needs into the target level and renumber the `sound:N` operands
|
||
([notes/editor-cross-import.md](../../notes/editor-cross-import.md)). Changing which sample an
|
||
object plays is a constant edit in its script ([Strats](../strats/custom-types.md)). Exporting or
|
||
replacing a sample's audio is not possible yet.
|
||
|
||
## Speech and dialogue
|
||
|
||
* **LGPC** holds the dialogue texts of a level in all languages plus a speech slot per line.
|
||
* A speech slot `#<hex>` is an index into **SRPC**, whose entries are offset/size pairs into the
|
||
global speech file `music/<language>.cvs` in the game folder (the German version ships
|
||
`english.cvs`).
|
||
* Strats show texts with opcodes 0xf0 / 0xfa (`topSay text:N`). Imported objects bring their
|
||
texts and speech references along.
|
||
|
||
The CVS file format itself was not analysed.
|