AM2 DTPK SND format This knowledge stems from Sappharad's work with some additions from Vincent and Preppy. Tables are generally padded for 4 byte read alignment. Most tables appear to be optional. Please note that all count values are 0-indexed, so add 1 to the value to get the count. This incrementing should be noted below in reference to all counts. All numeric values are Little Endian 0x00 - 4 bytes - Header: DTPK 0x04 - 4 bytes - 32 bit DTPK ID 0x08 - 4 bytes - 32 bit Size of file 0x20 - 4 bytes - 32 bit Combination Table Location 0x24 - 4 bytes - 32 bit Program Definitions Table Location 0x28 - 4 bytes - 32 bit Unknown Table Location 0x2c - 4 bytes - 32 bit Sequencer Table Location 0x30 - 4 bytes - 32 bit Sample Playback Information Table Location 0x34 - 4 bytes - 32 bit Intelligent Control Sound (ICS) Table Location 0x38 - 4 bytes - 32 bit Effects Table Location 0x3C - 4 bytes - 32 bit Sample Table Location ====Combination Table 0x00 - 2 bytes - Count of entries (Add 1 for number of combinations. Maximum value is 0x80/0n128 for a total of 0n129 entries.) 0x02 - Start of Entry offsets (0x02 bytes each) (end of Entry offsets) - Combination Entries Combination entry 0x00 is the SE entry Further entries are Song/Instrument entries Combination Entry: 0x00 - 1 byte - 8 bit Count Timbre entries (Add 1 for number of timbres) 0x01 - 1 byte - 8 bit Volume (0-0x127) 0x08 - Start of Timbre entries (0x20 bytes each) Timbre Entry: 0x00 - 1 byte - 8 bit state 0x00: Muted 0x80: Active 0x01 - 1 byte - 4 bit MIDI to use (0x00-0x0f) 0x07 - 1 byte - FX Values High 4 bits: FX Snd (0-0x0f) Low 4 bits: FX Channel (0-0x0f) 0x08 - 1 byte - 4 bit Range 0x09 - 1 byte - 4 bit Volume 0x0a - 1 byte - 8 bit Pan 0x00: Center 0x01-0x0f: Pan Right 0x10-0x1f: Pan Left 0x0b - 1 byte - signed 8 bit Trans (0xc0-0x3f) 0x0c - 1 byte - signed 8 bit Tune (0xc0-0x3f) ====Sequencer Table 0x00 - 4 bytes - Count of Sequencer Groups (Add 1 for number of groups) 0x04 - Start of Sequencer Group Label entries (0x04 bytes each) (end of Sequencer Group Label Entries) - Start of Sequencer Groups (variable length) Sequencer Group Label Entry: 0x00 - 2 bytes - 16 bit offset from start of Sequencer Table for that Group's Definition Table 0x02 - 1 byte - 8 bit Bank ID (as shown/used in SF2) 0x03 - 1 byte - 8 bit Group Type A8 - SONG A9 - SFX (area 1) AA - SFX (area 2) AB - SFX (area 3) AC - SFX or SONG (area 1) AD - SFX or SONG (area 2) Sequencer Group Definition Table: 0x00 - 4 bytes - Count Tracks (Add 1 for number of tracks) 0x04 - Start of Track Composition Data Locations (0x04 bytes each) (end of Track Composition Data locations) - Start of Track Composition Data Track Composition Data Location: 0x00 - 4 bytes - Offset from start of Sequencer Table for that Track's Composition Entry Track Composition Entry: 0x00 - 1 byte - Track Type 0x20-0x7f: SONG 0x20: audio playback by external device 0x40: audio playback by internal device (AICA) 0x60: audio playback by both 0xA0-0xFF: TRACK Track High 4 byte values: 0x10: use the sequencer group value 0xa0: audio playback by external device 0xc0: audio playback by internal device (AICA) 0xe0: audio playback by both Track Low 4 bytes: 0x0n: Sequencer group 'n' Further reads fork: SONG: (unknown) TRACK: 0x00 - 1 byte - 4 bit Entry Type OR'd with 4 bit Sync Level Values 0x00-0x7f - Sync level (0-127). 0x01 - 1 byte - Sync group (0-127) 0x02 - 1 byte - Entry Type Values 0xA0-0xFF - Entry Type Entry Type values: 0xA0: System Event 0xA4: FX Channel 0xA9: Request Bank Entry 0xDC-0xDF: Playback PCM If System Event: 0x00 - 1 byte - Event ID Event ID values: 0x00: Control Switch 0x01: Total Volume 0x02: Song Pause 0x03: Song Continue 0x04: Song Volume 0x05: Song Volume Bias 0x06: Song Tempo Bias 0x07: Song Transpose 0x09: Fade In 0x0a: Fade Out 0x10: SE Volume 0x1a: MIDI Port Change 0x1b: Hard Volume 0x20: Sync Level 0x24: Status Display 0x28: Silent On 0x29: Silent Off 0x01 - 1 byte - 4 bit Event Value OR'd with 0x80 Event Values meaning if Control Switch entry: 0x00: NULL 0x01: All Sound Off 0x02: All Song Off 0x03: All SE Off 0x04: All ICS Off 0x08: Stereo SW 0x09: Mono SW 0x0a: MIDI Thru On 0x0b: MIDI Thru Off 0x0c: MIDI Internal 0x0d: MIDI External 0x0e: MIDI Both 0x0f: Request Thru On 0x10: Request Thru Off 0x11: Port Sound Off 0x12: Port Song Off 0x13: Port SE Off If FX Channel: 0x00 - 1 byte - Request Request values: 0x10: Relevel 0x20: Pan 0x01 - 1 byte - 4 bit value OR'd with 0x80 If Request Bank Entry: 0x00 - 1 byte - Bank number to use 0x01 - 1 byte - Unknown value If Playback PCM: 0x00 - 1 byte - Sample Playback Definition ID low bits (0x00-0x7f). The high bits are stored in the penultimate byte. Note that for tracks with joined SPDs, the high bits of the last SPD are stored. So if you traverse a bit boundary as in 0x7f joined with 0x80, the high bit is set to 0xx1, and then you need to know to use 0xx0 for the first reference. 0x01 - 1 byte - Volume 0x02 - 1 byte - Either End Track (0x8x) or Join (0x00) The End Track value low bits are the high bits of the SPD ID. So ((End_Track_Value & 0x0f) << 7) gets you the high bits you want. Note as per above that for a Joined track that traverses bit boundaries (0x7f -> 0x80), the End Track lot bits being set to the high bits of the last referenced SPD. You need to know to use N-1 once you hit the bit boundary (x % 0x80 == 0). Joined Entry: 0x00 - 1 byte - Join Delay OR'd with 0x80 0x01 - 1 byte - Optional: 2nd Join Delay value Join Delay Math: delayIn44100Samples = (int(math.floor(unMaskedByte1 / 2)) * 11264) + ((unMaskedByte1 % 2) * 5120) delayIn44100Samples += int(math.floor(unMaskedByte2 / 23)) * 1024 If Joined, next byte starts the repeat of the Used Entry - 1 byte - Terminal Byte (0xFF) ====Sample Playback Table 0x10 - 1 byte - Sample Playback Information Count (Add 1 for number of entries) 0x50 - Start of Sample Playback Information entries (0x40 bytes each) Sample Playback Information Entry: 0x00 - 1 byte - SPI ID. Note that you can have more than 0xff count entries. The extra high bits (0xff00) are thrown away, so know to keep track of absolute count (true SPI ID) rather than just the listed SPI ID value. 0x02 - 1 byte - Sample Used For Entry 0x06 - 1 byte - Pan. 0x00 - 0x1f or 0x80. Default 0x80 (Combi). 0x00 == Center. 0x80 == Combi. 0x10-1f == Pan left. 0x01-0x0f == Pan right. 0x07 - 1 byte - Gain/Range. 0x00 - 0x0f or 0x80. Default 0x0c. 0x09 - 2 bytes - Combination of Rate, Transposition Base Note, and Detune. Detune math is around: if nDetune > 0x7f: nDetune = ((0xFF + 0x1F) - nDetune) * -1 else: nDetune = nDetune - 0x1e # For rates, the Hz frequency is listed first, and the DTPK rate value is listed second. # Note that that table overflows above 42000, so 44kHz appears to be rate value 0x0000. rateDictionary16bit = { 4000 : 0xd61d, 6000 : 0xdd1e, 6500 : 0xde36, 7000 : 0xe008, 8000 : 0xe21d, 8012 : 0xe21e, 8500 : 0xe320, 9000 : 0xe41f, 9500 : 0xe51c, 10500 : 0xe70a, 11025 : 0xe800, 12000 : 0xe91e, 12500 : 0xea0b, 13000 : 0xea36, 14000 : 0xec08, 15000 : 0xed15, 16000 : 0xee1d, 17000 : 0xef20, 18000 : 0xf01f, 19000 : 0xf11c, 20000 : 0xf214, 21000 : 0xf30a, 22050 : 0xf400, 23000 : 0xf42f, # everything above is real. # everything following is speculative! 24000 : 0xf4f6, 25000 : 0xf600, 26000 : 0xf71d, 28000 : 0xf800, 30000 : 0xf900, 32000 : 0xfa13, 34000 : 0xfb00, 35000 : 0xfc1d, 38000 : 0xfd15, 40000 : 0xfe1d, 42000 : 0xff00 } rateLowDictionary16bit = { 44100 : 0x0000, 45000 : 0x0100, 46000 : 0x0200, 47000 : 0x0300, 48000 : 0x0400, 49000 : 0x0500 } 0x0c: 1 byte - Attack Sustain Decay flags 1 0x0d: 1 byte - Attack Sustain Decay flags 2 0x0e: 1 byte - Attack Sustain Decay flags 3 0x0f: 1 byte - Attack Sustain Decay flags 4 Decay Level Low Bits = (((ASDf3 | 0x1f) ^ 0xff) ) >> 5 Decay Level High Bits = ((ASDf4 ^ 0xff) & 0x03) << 3 Attack Rate: ASDf1 & 0x1f. Values: 0-0x1f. Default 0x1f. Decay Rate 1: (ASDf1 >> 6) + ((ASDf2 & 0x07) << 2). Values 0-0x1f. Default 0. Decay Level = Decay Level Low Bits + Decay Level High Bits. Values 0-0x1f. Default 0x1f. Decay Rate 2 = ((ASDf2 >> 3)). Values 0-0x1f. Default 0. Release Rate = ASDf3 & 0x1f. Values: 0-0x1f. Default 0x1f. Key Rate Scaling = (ASDf4 & 0x3c) >> 2. Values: 0-0x0f. Default 0. LPLink = (ASDf4 >> 6) & 0x01. Values: Off/On. Default Off (0). # There should be bitmath to get to this point, but I wasn't getting it exactly # right and thus I'm just going to skip that and use a lookup table. DTPK127Encoding = [ 0x000, 0x389, 0x392, 0x398, 0x3a4, 0x3ad, 0x3b6, 0x3bf, # 0-7 0x3c8, 0x3d1, 0x3da, 0x3e3, 0x3ec, 0x3f5, 0x3fe, 0x407, # 8-15 0x410, 0x419, 0x422, 0x42b, 0x434, 0x43d, 0x446, 0x44f, # 16-23 0x458, 0x461, 0x46a, 0x473, 0x47c, 0x485, 0x48e, 0x497, # 24-31 0x4a0, 0x4a9, 0x4b2, 0x4bb, 0x4c4, 0x4cd, 0x4d6, 0x4df, # 32-39 0x4e8, 0x4f1, 0x4fa, 0x503, 0x50c, 0x515, 0x51e, 0x527, # 40-47 0x530, 0x539, 0x542, 0x54b, 0x554, 0x55d, 0x566, 0x56f, # 48-55 0x578, 0x581, 0x58a, 0x593, 0x59c, 0x5a5, 0x5ae, 0x5b7, # 56-63 0x5c0, 0x5c9, 0x5d2, 0x5db, 0x5e4, 0x5ed, 0x5f6, 0x5ff, # 64-71 0x608, 0x611, 0x61a, 0x623, 0x62c, 0x635, 0x63e, 0x647, # 72-79 0x650, 0x659, 0x662, 0x66b, 0x674, 0x67d, 0x686, 0x68f, # 80-87 0x698, 0x6a1, 0x6aa, 0x6b3, 0x6bc, 0x6c5, 0x6ce, 0x6d7, # 88-95 0x6e0, 0x6e9, 0x6f2, 0x6fb, 0x704, 0x70d, 0x716, 0x71f, # 96-103 0x728, 0x731, 0x73a, 0x743, 0x74c, 0x755, 0x75e, 0x767, # 104-111 0x770, 0x779, 0x782, 0x78b, 0x794, 0x79d, 0x7a6, 0x7af, # 112-119 0x7b8, 0x7c1, 0x7ca, 0x7d3, 0x7dc, 0x7e5, 0x7ee, 0x7fd # 120-127 ] 0x10: 1 byte - Low Pass Filter Flags 1 0x11: 1 byte - Low Pass Filter Flags 2 LPF Frequency 0 = DTPK127Encoding(((LPFFlags2 & 0x07) << 8) + LPFFlags1) Values 0-0x7f. Default 0. LPF Attack Rate = (LPFFlags2 & 0xf8) >> 3. Values 0-0x1f. Default 0. 0x12: 1 byte - Low Pass Filter Flags 1 0x13: 1 byte - Low Pass Filter Flags 2 LPF Frequency 1 = DTPK127Encoding(((LPFFlags2 & 0x07) << 8) + LPFFlags1). Values 0-0x7f. Default 0x7f. LPF Decay Rate 1 = (LPFFlags2 & 0xf8) >> 3. Values 0-0x1f. Default 0. 0x14: 1 byte - Low Pass Filter Flags 1 0x15: 1 byte - Low Pass Filter Flags 2 LPF Frequency 2 = DTPK127Encoding(((LPFFlags2 & 0x07) << 8) + LPFFlags1) Values 0-0x7f. Default 0x7f. LPF Decay Rate 2 = (LPFFlags2 & 0xf8) >> 3. Values 0-0x1f. Default 0. 0x16: 1 byte - Low Pass Filter Flags 1 0x17: 1 byte - Low Pass Filter Flags 2 LPF Frequency 3 = DTPK127Encoding(((LPFFlags2 & 0x07) << 8) + LPFFlags1) Values 0-0x7f. Default 0x7f. LPF Release Rate = (LPFFlags2 & 0xf8) >> 3. Values 0-0x1f. Default 0. 0x18: 1 byte - Low Pass Filter Flags 1 0x19: 1 byte - Low Pass Filter Flags 2 LPF Frequency 4 = DTPK127Encoding(((LPFFlags2 & 0x07) << 8) + LPFFlags1) Values 0-0x7f. Default 0x7f. 0x1e: 1 byte - FX override. 0-0x0f or 0x80 (Combi). Default 0. 0x1f: 1 byte - FX Flags. FX Channel = FXFlags & 0x0f. Default 0 FX Send = (FXFlags & 0xf0) >> 4. Default 0. 0x22: 1 byte - Group override flags. Default 0. 0x00: No group / polyphonic 0x40: No group / polyphonic, self priority 0. 0x80: Mono/last priority for self. 0x81: Last arrival priority. Decrement group priority by 1. 0x82: First arrival priority. 0xc0: Mono/last priority for self, self priority 0. 0xc1: Last arrival priority, self priority 0. 0xc2: First arrival priority, self priority 0. 0x23: 1 byte - Group Priority. Default 0. 0x24: 1 byte - Self Priority. Default 0. 0x25: 1 byte - Low Pass Filter Q. Setting is (value & 0xf8) >> 3. Values: 0-0x29. Default 4. 0x28: 1 byte - Random Tune. Default 0. Values 0-0x0f. 0x2e: 1 byte - Low Frequency Oscillation Delay. Values 0-0xff. Default 0. 0x2f: 1 byte - Low Frequency Oscillation Feed. Values 0-0xff. Default 0. 0x30: 1 byte - Low Frequency Oscillation depth flags LFO Pitch Depth = (LFOdf & 0xf0) >> 5. Values 0-0x07. Default 0 (Off). LFO Amplifier Depth = LFOdf & 0x07. Values 0-0x07. Default 0 (Off). LFO Amplifier Waveform: (LFOdf >> 3) & 0x03. Default 0 (Saw). Waveforms values: Saw (0), Square (1), Triangle (2), Noise (3). 0x31: 1 byte - Low Frequency Oscillation form flags LFO Pitch Waveform = LFOff & 0x03. Default 0 (Saw). LFO Speed = (LFOff & 0x7f) >> 2. Values 0-0x1f. Default 0. LFO SYnc = (LFOff & 0x80) >> 0x07. Values 0-0x01. Default 1 (On). ====Effects Table: 0x00 - 4 bytes - 32 bit Count of Effects Table Groups (Add 1 for number of groups) 0x04 - Start of Effects Table Group entries Effects Table Group Entry: 0x00 to 0x24 - 18 entries of 2 bytes each. Each entry represents the PAN and VOLUME values for each channel. PAN values: 0x00 = Center 0x01-0xF = Right Pan 1-15 0x11-0x1F = Left Pan 1-15 VOLUME values: 0x00-0x0F = Volume 0-15 0x24 to 0xc24 - FPD Chunks controlling reverb, fades, chorus, pitch, etc. ====Sample Table: 0x00 - 4 bytes - 32 bit Index of last sample (Add 1 for number of samples) 0x04 - Start of Sample entries (0x10 bytes each) Sample Entry: 0x00 - 4 bytes - 32 bit Sample Location & Type +- & 0x007FFFFF - Sample offset +- & 0x00800000 - Sample quality. 0 Normal, 1 Half +- & 0x01000000 - Format flag - 0 PCM, 1 ADPCM +- & 0x02000000 - Unknown flag. Is NOT Mono/Stereo 0x04 - 2 bytes - 16 bit Loop start offset from start of sample 0x06 - 2 bytes - 16 bit Loop end offset from start of sample 0x08 - 4 bytes - 32 bit value, either 0 or 0x80. 0x00 == Mono, 0x80 == Stereo 0x0C - 4 bytes - 32 bit length of sample data