tightening formats

This commit is contained in:
minjaesong
2026-04-23 14:47:53 +09:00
parent bc16ffabb4
commit 44f11120d8
3 changed files with 24 additions and 23 deletions

View File

@@ -16,7 +16,7 @@ const NUM_PATTERNS_MAX = 256
const NUM_CUES = 1024 const NUM_CUES = 1024
const CUE_SIZE = 32 // bytes per cue entry (packed 12-bit×20 voices + instruction + pad) const CUE_SIZE = 32 // bytes per cue entry (packed 12-bit×20 voices + instruction + pad)
// Signature written into the file (16 bytes, space-padded) // Signature written into the file (14 bytes, space-padded)
const CAPTURE_SIGNATURE = "LibTaud/TSVM " const CAPTURE_SIGNATURE = "LibTaud/TSVM "
// ── Internal helpers ──────────────────────────────────────────────────────── // ── Internal helpers ────────────────────────────────────────────────────────
@@ -205,8 +205,8 @@ function captureTrackerDataToFile(outFile) {
(compressedSize >>> 8) & 0xFF, (compressedSize >>> 8) & 0xFF,
(compressedSize >>> 16) & 0xFF, (compressedSize >>> 16) & 0xFF,
(compressedSize >>> 24) & 0xFF, (compressedSize >>> 24) & 0xFF,
// reserved (2) // reserved (4)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
].concat(sigBytes) // 8 + 2 + 4 + 2 + 16 = 32 bytes ].concat(sigBytes) // 8 + 2 + 4 + 2 + 16 = 32 bytes
// -- 6. Build song-table row (16 bytes) ----------------------------------- // -- 6. Build song-table row (16 bytes) -----------------------------------
@@ -219,7 +219,9 @@ function captureTrackerDataToFile(outFile) {
numPats & 0xFF, (numPats >>> 8) & 0xFF, // numPatterns Uint16 LE numPats & 0xFF, (numPats >>> 8) & 0xFF, // numPatterns Uint16 LE
bpmStored, // BPM with 24 bias bpmStored, // BPM with 24 bias
tickRate, // initial tick-rate tickRate, // initial tick-rate
0,0,0,0,0,0,0, // 7 bytes padding 0x40,0, // basenote
0x13,0xd0,0x82,0x43, // basefreq
0, // padding
] ]
// -- 7. Write header (creates / truncates file) --------------------------- // -- 7. Write header (creates / truncates file) ---------------------------

View File

@@ -87,7 +87,7 @@ NUM_PATTERNS_MAX = 4095
NUM_CUES = 1024 NUM_CUES = 1024
CUE_SIZE = 32 # packed 12-bit×20 voices + instruction + pad CUE_SIZE = 32 # packed 12-bit×20 voices + instruction + pad
NUM_VOICES = 20 NUM_VOICES = 20
SIGNATURE = b"s3m2taud/TSVM " # 16 bytes SIGNATURE = b"s3m2taud/TSVM " # 14 bytes
# Taud note constants # Taud note constants
NOTE_NOP = 0xFFFF NOTE_NOP = 0xFFFF
@@ -860,13 +860,13 @@ def assemble_taud(h: S3MHeader, instruments: list, patterns: list) -> bytes:
song_offset = TAUD_HEADER_SIZE + comp_size + TAUD_SONG_ENTRY song_offset = TAUD_HEADER_SIZE + comp_size + TAUD_SONG_ENTRY
num_taud_pats = P * C num_taud_pats = P * C
# Header (32 bytes): magic(8)+ver(1)+numSongs(1)+compSize(4)+rsvd(2)+sig(16) # Header (32 bytes): magic(8)+ver(1)+numSongs(1)+compSize(4)+rsvd(4)+sig(14)
sig = (SIGNATURE + b' ' * 16)[:16] sig = (SIGNATURE + b' ' * 14)[:14]
header = ( header = (
TAUD_MAGIC + TAUD_MAGIC +
bytes([TAUD_VERSION, 1]) + bytes([TAUD_VERSION, 1]) +
struct.pack('<I', comp_size) + struct.pack('<I', comp_size) +
b'\x00\x00' + b'\x00\x00\x00\x00' +
sig sig
) )
assert len(header) == TAUD_HEADER_SIZE assert len(header) == TAUD_HEADER_SIZE
@@ -893,7 +893,7 @@ def assemble_taud(h: S3MHeader, instruments: list, patterns: list) -> bytes:
pat_bin, pat_remap, num_taud_pats = deduplicate_patterns(bytes(pat_bin), orig_count) pat_bin, pat_remap, num_taud_pats = deduplicate_patterns(bytes(pat_bin), orig_count)
vprint(f" patterns: {orig_count}{num_taud_pats} unique ({orig_count - num_taud_pats} deduplicated)") vprint(f" patterns: {orig_count}{num_taud_pats} unique ({orig_count - num_taud_pats} deduplicated)")
# Song table row (16 bytes): offset(4)+voices(1)+patsLo(1)+patsHi(1)+bpm(1)+tick(1)+pad(7) # Song table row (16 bytes): offset(4)+voices(1)+patsLo(1)+patsHi(1)+bpm(1)+tick(1)+basenote(2)+basefreq(4)+pad(1)
# Built after dedup so num_taud_pats reflects the unique count. # Built after dedup so num_taud_pats reflects the unique count.
num_taud_pats_lo = num_taud_pats & 0xFF num_taud_pats_lo = num_taud_pats & 0xFF
num_taud_pats_hi = (num_taud_pats >> 8) & 0xFF num_taud_pats_hi = (num_taud_pats >> 8) & 0xFF
@@ -904,7 +904,7 @@ def assemble_taud(h: S3MHeader, instruments: list, patterns: list) -> bytes:
num_taud_pats_hi, num_taud_pats_hi,
bpm_stored, bpm_stored,
speed, speed,
) + b'\x00' * 7 ) + b'\x40\x00' + b'\x13\xd0\x82\x43' + b'\x00'
assert len(song_table) == TAUD_SONG_ENTRY assert len(song_table) == TAUD_SONG_ENTRY
# Cue sheet (using remapped pattern indices) # Cue sheet (using remapped pattern indices)

View File

@@ -2200,8 +2200,8 @@ Endianness: Little
Uint8 Format version (always 1) Uint8 Format version (always 1)
Uint8 Number of songs in SONG TABLE Uint8 Number of songs in SONG TABLE
Uint32 Compressed size of SAMPLE+INST section (used to calculate offset to SONG TABLE) Uint32 Compressed size of SAMPLE+INST section (used to calculate offset to SONG TABLE)
Uint16 Reserved for future versions Uint32 Reserved for Taud Project Format. Fill with zero
Byte[16]Tracker/Converter signature Byte[14]Tracker/Converter signature
## SONG TABLE ## SONG TABLE
Rows of 16 bytes: Rows of 16 bytes:
@@ -2210,7 +2210,7 @@ Rows of 16 bytes:
Uint16 Number of patterns (0 is invalid. pattern bin length = numPats * 8 bytes) Uint16 Number of patterns (0 is invalid. pattern bin length = numPats * 8 bytes)
Uint8 Initial BPM (bias of -24. 0x00=24, 0xFF=279) Uint8 Initial BPM (bias of -24. 0x00=24, 0xFF=279)
Uint8 Initial Tickrate (0 is invalid) Uint8 Initial Tickrate (0 is invalid)
Uint16 Current Tuning base note (1-4094), assuming octave 3. C3 (the default value) is 0x4000. If zero, assume the default value Uint16 Current Tuning base note (1..65533), assuming octave 3. C3 (the default value) is 0x4000. If zero, assume the default value
Float32 Frequency at the base note. Default (A440) is 261.6255653. If zero, assume the default value Float32 Frequency at the base note. Default (A440) is 261.6255653. If zero, assume the default value
Byte[1] Reserved for future versions Byte[1] Reserved for future versions
@@ -2239,12 +2239,11 @@ Endianness: Little
## Header ## Header
Byte[8] Magic Byte[8] Magic
Uint8 Format version (always 129) Uint8 Format version (always 129; high-bit set and number 0x01)
Uint8 Number of songs in SONG TABLE Uint8 Number of songs in SONG TABLE
Uint32 Compressed size of SAMPLE+INST section (used to calculate offset to SONG TABLE) Uint32 Compressed size of SAMPLE+INST section (used to calculate offset to SONG TABLE)
Uint16 Offset to Project Data (low twobyte) Uint32 Offset to Project Data (low twobyte)
Byte[14]Tracker/Converter signature Byte[14]Tracker/Converter signature
Uint16 Offset to Project Data (high twobyte)
## Project Data ## Project Data
Byte[8] Magic (\x1E T a u d P r J) Byte[8] Magic (\x1E T a u d P r J)
@@ -2268,11 +2267,11 @@ prefixes:
* PCpr. Project copyright string. Encoding: UTF-8 * PCpr. Project copyright string. Encoding: UTF-8
* PNam. Project name. Encoding: UTF-8 * PNam. Project name. Encoding: UTF-8
* INam. Instrument name table. Strings separated by comma * INam. Instrument name table. Strings separated by 0x1E
* pNam. Pattern name table. Strings separated by comma * pNam. Pattern name table. Strings separated by 0x1E
* SNam. Sample name table. Strings separated by comma * SNam. Sample name table. Strings separated by 0x1E
* sMet. Song metadata table * sMet. Song metadata table
* Repetition of: * Repetition of:
@@ -2288,15 +2287,15 @@ prefixes:
Uint8 Notation index (starting from zero) used by songs Uint8 Notation index (starting from zero) used by songs
Uint32 Size of this notation following this field Uint32 Size of this notation following this field
Uint8 Flags Uint8 Flags
0b nnnn 000t 0b 0000 000t
t: NOT using interval system (you are responsible for defining every notes expressible) t: NOT using interval system (you are responsible for defining every notes expressible)
Uint8 Reserved Uint8 Reserved
Float32 Interval size (octave system = 2.0f). If Flag 't' is set, this must be NaN. 0f and Infinity are considered illegal Float32 Interval size (octave system = 2.0f). If Flag 't' is set, this must be NaN. 0f and Infinity are considered illegal
Uint16 Notes between interval MINUS ONE (or octave); 12-TET will have value 11. 0 is considered illegal Uint16 Notes between interval MINUS ONE (or octave); 12-TET will have value 11. 0 is considered illegal
Byte[8] Reserved Byte[8] Reserved
Byte[*] Name, null terminated. Encoding: UTF-8 Byte[*] Name, null terminated. Encoding: UTF-8
Byte[*] Notation table. Comma-separated and null-terminated. Encoding: raw bytes Byte[*] Notation table. 0xFF-separated and null-terminated. Encoding: raw bytes
Uint16[*] Frequency table. Size of the table is defined by "Notes between interval MINUS ONE". All relative to the base note (Song table will be referred), in 4096-TET note number. Index zero of this table will be 0x0 if you read the spec right Uint16[*] Frequency table. Size of the table is defined by "Notes between interval MINUS ONE". This is a lookup table of relative pitch offsets (against the base tuning note) in 4096-TET space. Index zero of this table will be 0x0 if you read the spec right
Note: custom notations will use internal index 65535 down to 65520 (index 0 = 65535, index 15 = 65520) Note: custom notations will use internal index 65535 down to 65520 (index 0 = 65535, index 15 = 65520)