diff --git a/TAUD_NOTE_EFFECTS.md b/TAUD_NOTE_EFFECTS.md index f62f634..9e63d6e 100644 --- a/TAUD_NOTE_EFFECTS.md +++ b/TAUD_NOTE_EFFECTS.md @@ -1014,8 +1014,8 @@ There is no separate "use fadeout" flag — both extremes share the same field, - L_gain = if (pan < 0x80) 1.0 else 1.0 - (pan - 128.0) / 128.0 - R_gain = if (pan < 0x80) pan / 128.0 else 1.0 - Panning-equal-power: - - L_gain = cos(pi*x / 512.0) - - R_gain = sin(pi*x / 512.0) + - L_gain = cos(πx / 512.0) + - R_gain = sin(πx / 512.0) - Amiga tone (both coarse and fine E/F pitch slides). The `slideArg` is a **raw tracker period-unit count** (no scaling), with sign matching linear mode (negative for E, positive for F). Coarse slides apply on every non-first tick; fine slides apply once on tick 0 — the per-step arithmetic is identical: - AMIGA_BASE_PERIOD = 428.0 (period at the Taud reference pitch C4 for a standard 8363 Hz instrument, NTSC clock — identical to PT "C-2" period 428) - period = AMIGA_BASE_PERIOD × 2^(−(noteVal − C4) / 4096) diff --git a/terranmon.txt b/terranmon.txt index 6833d60..ee54909 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -2327,8 +2327,8 @@ TODO: 2026-05-06 .taud files predate the P bit and need re-conversion for pan/pf envelopes to play. See byte 15/17/19 spec for the LOOP word bit layout. - [ ] implement extended tone mode (MONOTONE compat) - [ ] pattern loops stops working after processed once (test with slumberjack.xm) + [x] slumberjack.xm: E6x commands are not processed + [ ] implement linear-freq tone mode (MONOTONE compat) [ ] milkytracker-style volume ramping (on sample-end only) diff --git a/xm2taud.py b/xm2taud.py index 26df9f5..cd34296 100644 --- a/xm2taud.py +++ b/xm2taud.py @@ -611,10 +611,11 @@ def encode_effect_xm(cmd: int, arg: int, ch: int = 0, row: int = 0, # Set finetune — convert to S5x sub-effect (4-bit signed nibble). return (TOP_S, 0x5000 | (val << 8), None, None) if sub == 0x6: - # Set loop point / loop. Taud S6x = fine pattern delay; the - # closest analogue here is dropping with a warn if val>0. - vprint(f" dropped E6{val:X} (set loop) at ch{ch} row{row}") - return (TOP_NONE, 0, None, None) + # XM E6x = pattern loop (E60 sets loop start, E6x with x>0 loops + # x times). Maps directly onto Taud SBx, which has identical + # semantics — the engine handles per-voice loopStartRow / + # loopCount in applySEffect (sub 0xB). + return (TOP_S, 0xB000 | (val << 8), None, None) if sub == 0x8: # Pan position 0..15 → set pan column (XM nybble × 17 → 8-bit). pan8 = (val << 4) | val