From 449885c1eac252834e2ee3e452104af48cc302a6 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Thu, 7 May 2026 02:01:30 +0900 Subject: [PATCH] minifloat redefined --- it2taud.py | 58 +------------- taud_common.py | 66 ++++++++++++++++ terranmon.txt | 77 ++++++++++--------- .../net/torvald/tsvm/ThreeFiveMinifloat.kt | 12 ++- xm2taud.py | 59 +------------- 5 files changed, 121 insertions(+), 151 deletions(-) diff --git a/it2taud.py b/it2taud.py index 4b0c123..e9c797f 100644 --- a/it2taud.py +++ b/it2taud.py @@ -53,7 +53,7 @@ from taud_common import ( EFF_U, EFF_V, EFF_W, EFF_X, EFF_Y, EFF_Z, J_SEMI_TABLE, d_arg_to_col, resample_linear, rescale_offset_effects, encode_cue, deduplicate_patterns, - normalise_sample, encode_song_entry, + normalise_sample, encode_song_entry, nearest_minifloat, CUE_INST_NOP, CUE_INST_HALT, CUE_INST_LEN, cue_instruction_len, ) @@ -117,60 +117,6 @@ IT_MEM_EFFECTS = frozenset({ SIGNATURE = b'it2taud/TSVM ' # 14 bytes -# ThreeFiveMiniUfloat LUT — 256 entries, seconds 0.0..126.0 (must match Kotlin) -_MINUFLOAT_LUT = [ - 0.0, 0.03125, 0.0625, 0.09375, 0.125, 0.15625, 0.1875, 0.21875, - 0.25, 0.28125, 0.3125, 0.34375, 0.375, 0.40625, 0.4375, 0.46875, - 0.5, 0.53125, 0.5625, 0.59375, 0.625, 0.65625, 0.6875, 0.71875, - 0.75, 0.78125, 0.8125, 0.84375, 0.875, 0.90625, 0.9375, 0.96875, - 1.0, 1.03125, 1.0625, 1.09375, 1.125, 1.15625, 1.1875, 1.21875, - 1.25, 1.28125, 1.3125, 1.34375, 1.375, 1.40625, 1.4375, 1.46875, - 1.5, 1.53125, 1.5625, 1.59375, 1.625, 1.65625, 1.6875, 1.71875, - 1.75, 1.78125, 1.8125, 1.84375, 1.875, 1.90625, 1.9375, 1.96875, - 2.0, 2.0625, 2.125, 2.1875, 2.25, 2.3125, 2.375, 2.4375, - 2.5, 2.5625, 2.625, 2.6875, 2.75, 2.8125, 2.875, 2.9375, - 3.0, 3.0625, 3.125, 3.1875, 3.25, 3.3125, 3.375, 3.4375, - 3.5, 3.5625, 3.625, 3.6875, 3.75, 3.8125, 3.875, 3.9375, - 4.0, 4.125, 4.25, 4.375, 4.5, 4.625, 4.75, 4.875, - 5.0, 5.125, 5.25, 5.375, 5.5, 5.625, 5.75, 5.875, - 6.0, 6.125, 6.25, 6.375, 6.5, 6.625, 6.75, 6.875, - 7.0, 7.125, 7.25, 7.375, 7.5, 7.625, 7.75, 7.875, - 8.0, 8.25, 8.5, 8.75, 9.0, 9.25, 9.5, 9.75, - 10.0, 10.25, 10.5, 10.75, 11.0, 11.25, 11.5, 11.75, - 12.0, 12.25, 12.5, 12.75, 13.0, 13.25, 13.5, 13.75, - 14.0, 14.25, 14.5, 14.75, 15.0, 15.25, 15.5, 15.75, - 16.0, 16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 19.5, - 20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.5, - 24.0, 24.5, 25.0, 25.5, 26.0, 26.5, 27.0, 27.5, - 28.0, 28.5, 29.0, 29.5, 30.0, 30.5, 31.0, 31.5, - 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, - 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, - 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, - 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, - 64.0, 66.0, 68.0, 70.0, 72.0, 74.0, 76.0, 78.0, - 80.0, 82.0, 84.0, 86.0, 88.0, 90.0, 92.0, 94.0, - 96.0, 98.0, 100.0, 102.0, 104.0, 106.0, 108.0, 110.0, - 112.0, 114.0, 116.0, 118.0, 120.0, 122.0, 124.0, 126.0, -] - -def _nearest_minifloat(sec: float) -> int: - """Return ThreeFiveMiniUfloat index (0-255) for the nearest representable seconds value.""" - if sec <= 0.0: - return 0 - if sec >= 126.0: - return 255 - lo, hi = 0, len(_MINUFLOAT_LUT) - 1 - while lo < hi: - mid = (lo + hi) // 2 - if _MINUFLOAT_LUT[mid] < sec: - lo = mid + 1 - else: - hi = mid - # lo is first index where LUT[lo] >= sec; check lo-1 for nearest - if lo > 0 and abs(_MINUFLOAT_LUT[lo - 1] - sec) <= abs(_MINUFLOAT_LUT[lo] - sec): - return lo - 1 - return lo - # ── IT header parser ────────────────────────────────────────────────────────── @@ -626,7 +572,7 @@ def _parse_it_envelope(data: bytes, env_ptr: int, kind: str, if k < len(nodes) - 1: _, next_tick = nodes[k + 1] delta_sec = max(0.0, (next_tick - tick) / ticks_per_sec) - mf_idx = _nearest_minifloat(delta_sec) + mf_idx = nearest_minifloat(delta_sec) else: mf_idx = 0 else: diff --git a/taud_common.py b/taud_common.py index a87884c..364a811 100644 --- a/taud_common.py +++ b/taud_common.py @@ -27,6 +27,9 @@ def vprint(*a, **kw) -> None: # ── Taud container constants ───────────────────────────────────────────────── TAUD_MAGIC = bytes([0x1F,0x54,0x53,0x56,0x4D,0x61,0x75,0x64]) +# Bumped 2026-05-07: envelope offset minifloat rebiased (smallest step 1/256 s, +# max 15.75 s; previously 1/32 s, max 126 s). v1 .taud envelopes will play with +# the wrong tempo on a v2 engine — re-convert from source. TAUD_VERSION = 1 TAUD_HEADER_SIZE = 32 # magic(8)+ver(1)+numSongs(1)+compSize(4)+projOff(4)+sig(14) TAUD_SONG_ENTRY = 32 # full spec entry (see encode_song_entry) @@ -103,6 +106,69 @@ EFF_U = 21; EFF_V = 22; EFF_W = 23; EFF_X = 24; EFF_Y = 25 EFF_Z = 26 +# ── Envelope offset minifloat ──────────────────────────────────────────────── +# +# Mirror of tsvm_core/.../ThreeFiveMinifloat.kt — used by every *2taud +# converter that emits envelope nodes. 3.5 unsigned minifloat (3-bit exponent +# + 5-bit mantissa) rebiased so the smallest non-zero step is 1/256 s ≈ 3.91 +# ms and the maximum is 15.75 s. The previous bias (1/32-step, max 126 s) +# under-resolved single-tick deltas at typical tracker BPMs. Every value here +# is the original LUT divided by 8. + +MINUFLOAT_LUT = ( + 0.0, 0.00390625, 0.0078125, 0.01171875, 0.015625, 0.01953125, 0.0234375, 0.02734375, + 0.03125, 0.03515625, 0.0390625, 0.04296875, 0.046875, 0.05078125, 0.0546875, 0.05859375, + 0.0625, 0.06640625, 0.0703125, 0.07421875, 0.078125, 0.08203125, 0.0859375, 0.08984375, + 0.09375, 0.09765625, 0.1015625, 0.10546875, 0.109375, 0.11328125, 0.1171875, 0.12109375, + 0.125, 0.12890625, 0.1328125, 0.13671875, 0.140625, 0.14453125, 0.1484375, 0.15234375, + 0.15625, 0.16015625, 0.1640625, 0.16796875, 0.171875, 0.17578125, 0.1796875, 0.18359375, + 0.1875, 0.19140625, 0.1953125, 0.19921875, 0.203125, 0.20703125, 0.2109375, 0.21484375, + 0.21875, 0.22265625, 0.2265625, 0.23046875, 0.234375, 0.23828125, 0.2421875, 0.24609375, + 0.25, 0.2578125, 0.265625, 0.2734375, 0.28125, 0.2890625, 0.296875, 0.3046875, + 0.3125, 0.3203125, 0.328125, 0.3359375, 0.34375, 0.3515625, 0.359375, 0.3671875, + 0.375, 0.3828125, 0.390625, 0.3984375, 0.40625, 0.4140625, 0.421875, 0.4296875, + 0.4375, 0.4453125, 0.453125, 0.4609375, 0.46875, 0.4765625, 0.484375, 0.4921875, + 0.5, 0.515625, 0.53125, 0.546875, 0.5625, 0.578125, 0.59375, 0.609375, + 0.625, 0.640625, 0.65625, 0.671875, 0.6875, 0.703125, 0.71875, 0.734375, + 0.75, 0.765625, 0.78125, 0.796875, 0.8125, 0.828125, 0.84375, 0.859375, + 0.875, 0.890625, 0.90625, 0.921875, 0.9375, 0.953125, 0.96875, 0.984375, + 1.0, 1.03125, 1.0625, 1.09375, 1.125, 1.15625, 1.1875, 1.21875, + 1.25, 1.28125, 1.3125, 1.34375, 1.375, 1.40625, 1.4375, 1.46875, + 1.5, 1.53125, 1.5625, 1.59375, 1.625, 1.65625, 1.6875, 1.71875, + 1.75, 1.78125, 1.8125, 1.84375, 1.875, 1.90625, 1.9375, 1.96875, + 2.0, 2.0625, 2.125, 2.1875, 2.25, 2.3125, 2.375, 2.4375, + 2.5, 2.5625, 2.625, 2.6875, 2.75, 2.8125, 2.875, 2.9375, + 3.0, 3.0625, 3.125, 3.1875, 3.25, 3.3125, 3.375, 3.4375, + 3.5, 3.5625, 3.625, 3.6875, 3.75, 3.8125, 3.875, 3.9375, + 4.0, 4.125, 4.25, 4.375, 4.5, 4.625, 4.75, 4.875, + 5.0, 5.125, 5.25, 5.375, 5.5, 5.625, 5.75, 5.875, + 6.0, 6.125, 6.25, 6.375, 6.5, 6.625, 6.75, 6.875, + 7.0, 7.125, 7.25, 7.375, 7.5, 7.625, 7.75, 7.875, + 8.0, 8.25, 8.5, 8.75, 9.0, 9.25, 9.5, 9.75, + 10.0, 10.25, 10.5, 10.75, 11.0, 11.25, 11.5, 11.75, + 12.0, 12.25, 12.5, 12.75, 13.0, 13.25, 13.5, 13.75, + 14.0, 14.25, 14.5, 14.75, 15.0, 15.25, 15.5, 15.75, +) + + +def nearest_minifloat(sec: float) -> int: + """Return the ThreeFiveMiniUfloat index (0..255) for the LUT entry nearest to `sec`.""" + if sec <= 0.0: + return 0 + if sec >= MINUFLOAT_LUT[-1]: + return 255 + lo, hi = 0, len(MINUFLOAT_LUT) - 1 + while lo < hi: + mid = (lo + hi) // 2 + if MINUFLOAT_LUT[mid] < sec: + lo = mid + 1 + else: + hi = mid + if lo > 0 and abs(MINUFLOAT_LUT[lo - 1] - sec) < abs(MINUFLOAT_LUT[lo] - sec): + return lo - 1 + return lo + + # ── Helpers ────────────────────────────────────────────────────────────────── def d_arg_to_col(arg: int): diff --git a/terranmon.txt b/terranmon.txt index ee54909..27c4a34 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -2137,13 +2137,13 @@ from source. (bits 14..15 reserved) 21 Bit16x25 Volume envelopes Byte 1: Volume (00..3F) - Byte 2: Time until the next point, in seconds (3.5 Unsigned Minifloat). 0 = hold at this point indefinitely. + Byte 2: Time until the next point, in seconds (3.5 Unsigned Minifloat, biased; range 0..15.75 s, smallest non-zero step 1/256 s ≈ 3.91 ms — chosen so single tracker ticks resolve at every supported BPM). 0 = hold at this point indefinitely. 71 Bit16x25 Panning envelopes Byte 1: Pan (00..FF) - Byte 2: Time until the next point, in seconds (3.5 Unsigned Minifloat). 0 = hold at this point indefinitely. + Byte 2: Time until the next point, in seconds (3.5 Unsigned Minifloat, biased; range 0..15.75 s, smallest non-zero step 1/256 s ≈ 3.91 ms — chosen so single tracker ticks resolve at every supported BPM). 0 = hold at this point indefinitely. 121 Bit16x25 Pitch/Filter envelopes Byte 1: Value (00..FF) - Byte 2: Time until the next point, in seconds (3.5 Unsigned Minifloat). 0 = hold at this point indefinitely. + Byte 2: Time until the next point, in seconds (3.5 Unsigned Minifloat, biased; range 0..15.75 s, smallest non-zero step 1/256 s ≈ 3.91 ms — chosen so single tracker ticks resolve at every supported BPM). 0 = hold at this point indefinitely. 171 Uint8 Instrument Global Volume (0..255) * ImpulseTracker has range of 0..128; multiply by (255/128) then round to int - ImpulseTracker also has samplewise default volume (0..64) and samplewise global volume (0..64), and they must be taken into account because Taud has no samplewise config, following the ImpulseTracker spec @@ -2464,40 +2464,45 @@ Play Head Flags 65536..131071 RW: PCM Sample buffer -Table of 3.5 Minifloat values (CSV) +Table of 3.5 Minifloat values (CSV). +Rebiased 2026-05-07 so the smallest non-zero step is 1/256 s and the maximum +is 15.75 s — every cell is the original LUT value divided by 8. Chosen for +tracker envelopes: a single song tick (≈ 8.9 ms at BPM 280, ≈ 41.7 ms at +BPM 24) now lands within ±17 % of an LUT entry across the whole supported +BPM range; the previous bias was ±150 % at common BPMs. ,000,001,010,011,100,101,110,111,MSB -00000,0,1,2,4,8,16,32,64 -00001,0.03125,1.03125,2.0625,4.125,8.25,16.5,33,66 -00010,0.0625,1.0625,2.125,4.25,8.5,17,34,68 -00011,0.09375,1.09375,2.1875,4.375,8.75,17.5,35,70 -00100,0.125,1.125,2.25,4.5,9,18,36,72 -00101,0.15625,1.15625,2.3125,4.625,9.25,18.5,37,74 -00110,0.1875,1.1875,2.375,4.75,9.5,19,38,76 -00111,0.21875,1.21875,2.4375,4.875,9.75,19.5,39,78 -01000,0.25,1.25,2.5,5,10,20,40,80 -01001,0.28125,1.28125,2.5625,5.125,10.25,20.5,41,82 -01010,0.3125,1.3125,2.625,5.25,10.5,21,42,84 -01011,0.34375,1.34375,2.6875,5.375,10.75,21.5,43,86 -01100,0.375,1.375,2.75,5.5,11,22,44,88 -01101,0.40625,1.40625,2.8125,5.625,11.25,22.5,45,90 -01110,0.4375,1.4375,2.875,5.75,11.5,23,46,92 -01111,0.46875,1.46875,2.9375,5.875,11.75,23.5,47,94 -10000,0.5,1.5,3,6,12,24,48,96 -10001,0.53125,1.53125,3.0625,6.125,12.25,24.5,49,98 -10010,0.5625,1.5625,3.125,6.25,12.5,25,50,100 -10011,0.59375,1.59375,3.1875,6.375,12.75,25.5,51,102 -10100,0.625,1.625,3.25,6.5,13,26,52,104 -10101,0.65625,1.65625,3.3125,6.625,13.25,26.5,53,106 -10110,0.6875,1.6875,3.375,6.75,13.5,27,54,108 -10111,0.71875,1.71875,3.4375,6.875,13.75,27.5,55,110 -11000,0.75,1.75,3.5,7,14,28,56,112 -11001,0.78125,1.78125,3.5625,7.125,14.25,28.5,57,114 -11010,0.8125,1.8125,3.625,7.25,14.5,29,58,116 -11011,0.84375,1.84375,3.6875,7.375,14.75,29.5,59,118 -11100,0.875,1.875,3.75,7.5,15,30,60,120 -11101,0.90625,1.90625,3.8125,7.625,15.25,30.5,61,122 -11110,0.9375,1.9375,3.875,7.75,15.5,31,62,124 -11111,0.96875,1.96875,3.9375,7.875,15.75,31.5,63,126 +00000,0,0.125,0.25,0.5,1,2,4,8 +00001,0.00390625,0.12890625,0.2578125,0.515625,1.03125,2.0625,4.125,8.25 +00010,0.0078125,0.1328125,0.265625,0.53125,1.0625,2.125,4.25,8.5 +00011,0.01171875,0.13671875,0.2734375,0.546875,1.09375,2.1875,4.375,8.75 +00100,0.015625,0.140625,0.28125,0.5625,1.125,2.25,4.5,9 +00101,0.01953125,0.14453125,0.2890625,0.578125,1.15625,2.3125,4.625,9.25 +00110,0.0234375,0.1484375,0.296875,0.59375,1.1875,2.375,4.75,9.5 +00111,0.02734375,0.15234375,0.3046875,0.609375,1.21875,2.4375,4.875,9.75 +01000,0.03125,0.15625,0.3125,0.625,1.25,2.5,5,10 +01001,0.03515625,0.16015625,0.3203125,0.640625,1.28125,2.5625,5.125,10.25 +01010,0.0390625,0.1640625,0.328125,0.65625,1.3125,2.625,5.25,10.5 +01011,0.04296875,0.16796875,0.3359375,0.671875,1.34375,2.6875,5.375,10.75 +01100,0.046875,0.171875,0.34375,0.6875,1.375,2.75,5.5,11 +01101,0.05078125,0.17578125,0.3515625,0.703125,1.40625,2.8125,5.625,11.25 +01110,0.0546875,0.1796875,0.359375,0.71875,1.4375,2.875,5.75,11.5 +01111,0.05859375,0.18359375,0.3671875,0.734375,1.46875,2.9375,5.875,11.75 +10000,0.0625,0.1875,0.375,0.75,1.5,3,6,12 +10001,0.06640625,0.19140625,0.3828125,0.765625,1.53125,3.0625,6.125,12.25 +10010,0.0703125,0.1953125,0.390625,0.78125,1.5625,3.125,6.25,12.5 +10011,0.07421875,0.19921875,0.3984375,0.796875,1.59375,3.1875,6.375,12.75 +10100,0.078125,0.203125,0.40625,0.8125,1.625,3.25,6.5,13 +10101,0.08203125,0.20703125,0.4140625,0.828125,1.65625,3.3125,6.625,13.25 +10110,0.0859375,0.2109375,0.421875,0.84375,1.6875,3.375,6.75,13.5 +10111,0.08984375,0.21484375,0.4296875,0.859375,1.71875,3.4375,6.875,13.75 +11000,0.09375,0.21875,0.4375,0.875,1.75,3.5,7,14 +11001,0.09765625,0.22265625,0.4453125,0.890625,1.78125,3.5625,7.125,14.25 +11010,0.1015625,0.2265625,0.453125,0.90625,1.8125,3.625,7.25,14.5 +11011,0.10546875,0.23046875,0.4609375,0.921875,1.84375,3.6875,7.375,14.75 +11100,0.109375,0.234375,0.46875,0.9375,1.875,3.75,7.5,15 +11101,0.11328125,0.23828125,0.4765625,0.953125,1.90625,3.8125,7.625,15.25 +11110,0.1171875,0.2421875,0.484375,0.96875,1.9375,3.875,7.75,15.5 +11111,0.12109375,0.24609375,0.4921875,0.984375,1.96875,3.9375,7.875,15.75 LSB ## Tracker Note Effects diff --git a/tsvm_core/src/net/torvald/tsvm/ThreeFiveMinifloat.kt b/tsvm_core/src/net/torvald/tsvm/ThreeFiveMinifloat.kt index f259747..3fd3217 100644 --- a/tsvm_core/src/net/torvald/tsvm/ThreeFiveMinifloat.kt +++ b/tsvm_core/src/net/torvald/tsvm/ThreeFiveMinifloat.kt @@ -1,7 +1,15 @@ package net.torvald.tsvm /** - * Created by minjaesong on 2022-12-30. + * 3.5 unsigned minifloat (3-bit exponent + 5-bit mantissa), scaled so the + * smallest non-zero step is 1/256 s ≈ 3.91 ms and the maximum representable + * value is 15.75 s. Used for Taud envelope point offsets — the resolution at + * the low end is fine enough to resolve individual tracker ticks at every + * supported BPM (worst case ±17 % at BPM 250+, vs. ±150 % under the original + * 1/32-step bias). + * + * Created by minjaesong on 2022-12-30. Rebiased for tracker tick resolution + * on 2026-05-07 (entire LUT divided by 8). */ @JvmInline value class ThreeFiveMiniUfloat(val index: Int = 0) { @@ -11,7 +19,7 @@ value class ThreeFiveMiniUfloat(val index: Int = 0) { } companion object { - val LUT = floatArrayOf(0f,0.03125f,0.0625f,0.09375f,0.125f,0.15625f,0.1875f,0.21875f,0.25f,0.28125f,0.3125f,0.34375f,0.375f,0.40625f,0.4375f,0.46875f,0.5f,0.53125f,0.5625f,0.59375f,0.625f,0.65625f,0.6875f,0.71875f,0.75f,0.78125f,0.8125f,0.84375f,0.875f,0.90625f,0.9375f,0.96875f,1f,1.03125f,1.0625f,1.09375f,1.125f,1.15625f,1.1875f,1.21875f,1.25f,1.28125f,1.3125f,1.34375f,1.375f,1.40625f,1.4375f,1.46875f,1.5f,1.53125f,1.5625f,1.59375f,1.625f,1.65625f,1.6875f,1.71875f,1.75f,1.78125f,1.8125f,1.84375f,1.875f,1.90625f,1.9375f,1.96875f,2f,2.0625f,2.125f,2.1875f,2.25f,2.3125f,2.375f,2.4375f,2.5f,2.5625f,2.625f,2.6875f,2.75f,2.8125f,2.875f,2.9375f,3f,3.0625f,3.125f,3.1875f,3.25f,3.3125f,3.375f,3.4375f,3.5f,3.5625f,3.625f,3.6875f,3.75f,3.8125f,3.875f,3.9375f,4f,4.125f,4.25f,4.375f,4.5f,4.625f,4.75f,4.875f,5f,5.125f,5.25f,5.375f,5.5f,5.625f,5.75f,5.875f,6f,6.125f,6.25f,6.375f,6.5f,6.625f,6.75f,6.875f,7f,7.125f,7.25f,7.375f,7.5f,7.625f,7.75f,7.875f,8f,8.25f,8.5f,8.75f,9f,9.25f,9.5f,9.75f,10f,10.25f,10.5f,10.75f,11f,11.25f,11.5f,11.75f,12f,12.25f,12.5f,12.75f,13f,13.25f,13.5f,13.75f,14f,14.25f,14.5f,14.75f,15f,15.25f,15.5f,15.75f,16f,16.5f,17f,17.5f,18f,18.5f,19f,19.5f,20f,20.5f,21f,21.5f,22f,22.5f,23f,23.5f,24f,24.5f,25f,25.5f,26f,26.5f,27f,27.5f,28f,28.5f,29f,29.5f,30f,30.5f,31f,31.5f,32f,33f,34f,35f,36f,37f,38f,39f,40f,41f,42f,43f,44f,45f,46f,47f,48f,49f,50f,51f,52f,53f,54f,55f,56f,57f,58f,59f,60f,61f,62f,63f,64f,66f,68f,70f,72f,74f,76f,78f,80f,82f,84f,86f,88f,90f,92f,94f,96f,98f,100f,102f,104f,106f,108f,110f,112f,114f,116f,118f,120f,122f,124f,126f) + val LUT = floatArrayOf(0f,0.00390625f,0.0078125f,0.01171875f,0.015625f,0.01953125f,0.0234375f,0.02734375f,0.03125f,0.03515625f,0.0390625f,0.04296875f,0.046875f,0.05078125f,0.0546875f,0.05859375f,0.0625f,0.06640625f,0.0703125f,0.07421875f,0.078125f,0.08203125f,0.0859375f,0.08984375f,0.09375f,0.09765625f,0.1015625f,0.10546875f,0.109375f,0.11328125f,0.1171875f,0.12109375f,0.125f,0.12890625f,0.1328125f,0.13671875f,0.140625f,0.14453125f,0.1484375f,0.15234375f,0.15625f,0.16015625f,0.1640625f,0.16796875f,0.171875f,0.17578125f,0.1796875f,0.18359375f,0.1875f,0.19140625f,0.1953125f,0.19921875f,0.203125f,0.20703125f,0.2109375f,0.21484375f,0.21875f,0.22265625f,0.2265625f,0.23046875f,0.234375f,0.23828125f,0.2421875f,0.24609375f,0.25f,0.2578125f,0.265625f,0.2734375f,0.28125f,0.2890625f,0.296875f,0.3046875f,0.3125f,0.3203125f,0.328125f,0.3359375f,0.34375f,0.3515625f,0.359375f,0.3671875f,0.375f,0.3828125f,0.390625f,0.3984375f,0.40625f,0.4140625f,0.421875f,0.4296875f,0.4375f,0.4453125f,0.453125f,0.4609375f,0.46875f,0.4765625f,0.484375f,0.4921875f,0.5f,0.515625f,0.53125f,0.546875f,0.5625f,0.578125f,0.59375f,0.609375f,0.625f,0.640625f,0.65625f,0.671875f,0.6875f,0.703125f,0.71875f,0.734375f,0.75f,0.765625f,0.78125f,0.796875f,0.8125f,0.828125f,0.84375f,0.859375f,0.875f,0.890625f,0.90625f,0.921875f,0.9375f,0.953125f,0.96875f,0.984375f,1f,1.03125f,1.0625f,1.09375f,1.125f,1.15625f,1.1875f,1.21875f,1.25f,1.28125f,1.3125f,1.34375f,1.375f,1.40625f,1.4375f,1.46875f,1.5f,1.53125f,1.5625f,1.59375f,1.625f,1.65625f,1.6875f,1.71875f,1.75f,1.78125f,1.8125f,1.84375f,1.875f,1.90625f,1.9375f,1.96875f,2f,2.0625f,2.125f,2.1875f,2.25f,2.3125f,2.375f,2.4375f,2.5f,2.5625f,2.625f,2.6875f,2.75f,2.8125f,2.875f,2.9375f,3f,3.0625f,3.125f,3.1875f,3.25f,3.3125f,3.375f,3.4375f,3.5f,3.5625f,3.625f,3.6875f,3.75f,3.8125f,3.875f,3.9375f,4f,4.125f,4.25f,4.375f,4.5f,4.625f,4.75f,4.875f,5f,5.125f,5.25f,5.375f,5.5f,5.625f,5.75f,5.875f,6f,6.125f,6.25f,6.375f,6.5f,6.625f,6.75f,6.875f,7f,7.125f,7.25f,7.375f,7.5f,7.625f,7.75f,7.875f,8f,8.25f,8.5f,8.75f,9f,9.25f,9.5f,9.75f,10f,10.25f,10.5f,10.75f,11f,11.25f,11.5f,11.75f,12f,12.25f,12.5f,12.75f,13f,13.25f,13.5f,13.75f,14f,14.25f,14.5f,14.75f,15f,15.25f,15.5f,15.75f) private fun fromFloatToIndex(fval: Float): Int { val (llim, hlim) = binarySearchInterval(fval, LUT) diff --git a/xm2taud.py b/xm2taud.py index cd34296..7156b05 100644 --- a/xm2taud.py +++ b/xm2taud.py @@ -53,7 +53,7 @@ from taud_common import ( SEL_SET, SEL_UP, SEL_DOWN, SEL_FINE, J_SEMI_TABLE, d_arg_to_col, resample_linear, rescale_offset_effects, encode_cue, deduplicate_patterns, - normalise_sample, encode_song_entry, + normalise_sample, encode_song_entry, nearest_minifloat, CUE_INST_NOP, CUE_INST_HALT, CUE_INST_LEN, cue_instruction_len, ) @@ -78,61 +78,6 @@ XM_ENV_LOOP = 0x04 SIGNATURE = b"xm2taud/TSVM " # 14 bytes -# ── Minifloat LUT (must match it2taud / engine) ────────────────────────────── - -_MINUFLOAT_LUT = [ - 0.0, 0.03125, 0.0625, 0.09375, 0.125, 0.15625, 0.1875, 0.21875, - 0.25, 0.28125, 0.3125, 0.34375, 0.375, 0.40625, 0.4375, 0.46875, - 0.5, 0.53125, 0.5625, 0.59375, 0.625, 0.65625, 0.6875, 0.71875, - 0.75, 0.78125, 0.8125, 0.84375, 0.875, 0.90625, 0.9375, 0.96875, - 1.0, 1.03125, 1.0625, 1.09375, 1.125, 1.15625, 1.1875, 1.21875, - 1.25, 1.28125, 1.3125, 1.34375, 1.375, 1.40625, 1.4375, 1.46875, - 1.5, 1.53125, 1.5625, 1.59375, 1.625, 1.65625, 1.6875, 1.71875, - 1.75, 1.78125, 1.8125, 1.84375, 1.875, 1.90625, 1.9375, 1.96875, - 2.0, 2.0625, 2.125, 2.1875, 2.25, 2.3125, 2.375, 2.4375, - 2.5, 2.5625, 2.625, 2.6875, 2.75, 2.8125, 2.875, 2.9375, - 3.0, 3.0625, 3.125, 3.1875, 3.25, 3.3125, 3.375, 3.4375, - 3.5, 3.5625, 3.625, 3.6875, 3.75, 3.8125, 3.875, 3.9375, - 4.0, 4.125, 4.25, 4.375, 4.5, 4.625, 4.75, 4.875, - 5.0, 5.125, 5.25, 5.375, 5.5, 5.625, 5.75, 5.875, - 6.0, 6.125, 6.25, 6.375, 6.5, 6.625, 6.75, 6.875, - 7.0, 7.125, 7.25, 7.375, 7.5, 7.625, 7.75, 7.875, - 8.0, 8.25, 8.5, 8.75, 9.0, 9.25, 9.5, 9.75, - 10.0, 10.25, 10.5, 10.75, 11.0, 11.25, 11.5, 11.75, - 12.0, 12.25, 12.5, 12.75, 13.0, 13.25, 13.5, 13.75, - 14.0, 14.25, 14.5, 14.75, 15.0, 15.25, 15.5, 15.75, - 16.0, 16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 19.5, - 20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.5, - 24.0, 24.5, 25.0, 25.5, 26.0, 26.5, 27.0, 27.5, - 28.0, 28.5, 29.0, 29.5, 30.0, 30.5, 31.0, 31.5, - 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, - 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, - 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, - 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, - 64.0, 66.0, 68.0, 70.0, 72.0, 74.0, 76.0, 78.0, - 80.0, 82.0, 84.0, 86.0, 88.0, 90.0, 92.0, 94.0, - 96.0, 98.0, 100.0, 102.0, 104.0, 106.0, 108.0, 110.0, - 112.0, 114.0, 116.0, 118.0, 120.0, 122.0, 124.0, 126.0, -] - - -def _nearest_minifloat(sec: float) -> int: - if sec <= 0.0: - return 0 - if sec >= 126.0: - return 255 - lo, hi = 0, len(_MINUFLOAT_LUT) - 1 - while lo < hi: - mid = (lo + hi) // 2 - if _MINUFLOAT_LUT[mid] < sec: - lo = mid + 1 - else: - hi = mid - if lo > 0 and abs(_MINUFLOAT_LUT[lo - 1] - sec) < abs(_MINUFLOAT_LUT[lo] - sec): - return lo - 1 - return lo - - # ── Data classes ───────────────────────────────────────────────────────────── class XMHeader: @@ -809,7 +754,7 @@ def _xm_envelope_to_taud(env_pts: list, num_pts: int, env_type: int, if k < len(nodes) - 1: next_frame, _ = nodes[k + 1] delta_sec = max(0.0, (next_frame - frame) / ticks_per_sec) - mf_idx = _nearest_minifloat(delta_sec) + mf_idx = nearest_minifloat(delta_sec) else: mf_idx = 0 else: