The NED File Format Reversed from Michel Iwaniec's replay22.asm Copyright (c) 2000 Damian Yerrick. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections or Cover Texts. A copy of the license can be found in COPYING.DOC (a text file, not a fsckin MS Word file). NerdTracker II (NT2) is a music tracker from NRU Software, available by email from Memblers <5010.0951@tcon.net>. Replay code exists to play NT2 modules (called NED files) on NES hardware; NT2 is very popular among NES demo musicians. Many homebrew NSF tracks are based on the NT2 system. One day I got bored and decided to reverse-engineer the format of a NED file. I created a file dumper. Armed with this disinformation (ABSOLUTELY NO WARRANTY is provided), it is possible to create replay code for platforms other than NES. == Structure of the NED file == off size 0 52(??)NT2 NED header (stripped when writing to .dat) 52(??) ??? NED temp.dat data The sample data has not yet been reversed. == Structure of the NED temp.dat file == off size 0 16 NED sequence header 16 128 Instruments 144 4*o Order table 144+4o 2*p0 Pattern offsets for square 1 ... 2*p1 Pattern offsets for square 2 ... 2*p2 Pattern offsets for triangle ... 2*p3 Pattern offsets for noise ... 2*p4 Pattern offsets for sample ... ... Pattern data == NT2 NED header == Has not been reversed. I'll have to use black box RE techniques to get at this, as the source code for nt2.exe is not available. == The NED sequence header == The replay code does not use NED files but instead temp.dat files. 0 NED_NedAddr points here 0 version (always 0x20) 1 header size (always 0x10) 2 flags (???) 3 initial ticks per row (always 0x06 in NT2-produced files) 4 loop point in song 5 number of instruments (always 0x10) 6 number of DPCM instruments 7 song length 8 number of squarewave1 patterns 9 number of squarewave2 patterns 10 number of triangle patterns 11 number of noise patterns 12 number of sample patterns 13-15 filler 16 NED_InstAddr points here == Instruments == Each instrument is eight bytes. Information marked with a (?) has not been fully verified against a real NED file. 0 76543210 `+|`---+- always 10000 |+------ note length (bit 7) +------- tone 1 automatic pitchbending 2 auto FM 3 auto AM 4 76543210 |`-----+- note length (bits 6-0) +-------- decay direction (0 down, 1 up) 5 76543210 `--+`--+- decay rate +----- initial volume 6 76543210 ||| `--+- arpeggio Z ||+------ nonlooped arpeggio |+------- use 93-bit noise waveform +-------- arpeggio direction (0 up, 1 down) (?) 7 76543210 `--+`--+- arpeggio X +----- arpeggio Y Order table NED_OrderAddr points to a list of 32-bit little-endian integers: 11111111 11111111 00000000 00000000 fedcba98 76543210 fedcba98 76543210 `----+`----+`---+`----+`---+- square 1 | | | +------ square 2 pattern | | +------------ triangle pattern | +----------------- noise pattern +----------------------- sample pattern Pattern pointers Each two-byte pattern pointer is an offset from NED_NedAddr to pattern data. Pattern data 00 ??? 01 number of rows used, minus 1 02 bit pattern (nibbles, LITTLE-endian) d0: note d1: inst d2: effect d3: effect data then data (starting on a byte boundary) Note data is a stream of nibbles. The most confusing part is that the nibble ordering for whole bytes is not the same as the nibble ordering for split bytes. Apparently, it works like this: pullbyte() { if(on even boundary) return getnextbyte(); else return (getnextnibble() << 4) | getnextnibble(); } A note number is an offset from C-0 (middle C is C-3 on square or C-4 on triangle). Examples: 12 is F-1 3/A is instrument 4 is effect 56 is effect data All notes on, starting on even nibble boundary: 12 43 56 Only note, starting on even nibble boundary: 12 Note and instrument, twice: 12 13 32 == Effects and their parameters == 1xx Portamento up, x = speed 2xx Portamento down, x = speed 3xx Portamento to basenote, x = speed 4xy FM, x = speed, y = depth 7xy AM, x = speed, y = depth 8xy Arpeggio, x and y semitones above basenote Axy Volume Slide, x = up, y = down Cxx Set volume, maximum is $3f (NES ignores 2 lsb) D00 Go to next pattern Fxx Set speed (50/xx rows per second) == Example source code == An NT2 temp.dat dumper (nt2dump.c) is included with this document; for best results, compile it with DJGPP: http://www.delorie.com/djgpp/