Compare commits

...

2 Commits

Author SHA1 Message Date
minjaesong
a1b62f3155 taud-related changes (docs, converter supports Y eff) 2026-04-24 18:35:24 +09:00
minjaesong
4802e10dfc better tracker font, IT eff for Taud 2026-04-24 12:18:34 +09:00
10 changed files with 45 additions and 20 deletions

2
.gitignore vendored
View File

@@ -68,3 +68,5 @@ assets/disk0/*.mov
assets/diskMediabin/*
video_encoder/*
assets/disk0/tvdos/bin/tautfont.png

View File

@@ -487,7 +487,7 @@ A tempo slide's memory slot is separate from the set-tempo path and is private t
**Plain.** Sets the global mix bus volume (0..$FF). $00 is silence; $FF is full. The default is $80.
**Compatibility.** ST3's global volume is 0..$40; convert with `taud_v = st3_v × 4`, clamped at $FF. On export, `st3_v = taud_v >> 2`, clamped at $40.
**Compatibility.** ST3's global volume is 0..$40; convert with `taud_v = st3_v × 4`, clamped at $FF. On export, `st3_v = taud_v >> 2`, clamped at $40. IT's global volume is 0..$80; convert with `taud_v = it_v × 2`, clamped at $FF.
**Implementation.** Write the high byte to `global_volume` on the row the command appears. The low byte is reserved. ST3's `kST3NoMutedChannels` rule applies: V on a muted channel is ignored by ST3; for strict-compatible playback Taud follows suit, but new Taud compositions should avoid muting channels that carry global effects.
@@ -517,6 +517,16 @@ Peak at maximum settings: $7F × $FF >> 9 = $3F — the full panning range. Retr
---
## X $xx00 — Set Panning
**Plain.** **Unimplemented**. On IT, sets the panning position of the current channel, $00 being full-left and $FF being full-right.
**Compatibility.** Convert directly into panning effect `0.$xx`, rounded down to nearest 6-bit value.
**Implementation.** Not applicable.
---
# The S subcommand family
S is a multiplexing opcode; the **high nibble of the high byte** selects the sub-effect, and the remainder is the sub-argument.

View File

@@ -70,7 +70,7 @@ middot:MIDDOT
}
const fxNames = {
A:"Set tick speed",
A:"Tick speed",
B:"Jump to order",
C:"Break pattern",
D:"Volume slide",
@@ -89,8 +89,8 @@ R:"Tremolo",
T:"Tempo",
V:"Global volume",
S:"Special",
S1:"Glissando ctrl",
S2:"Sample finetune",
S1:"Gliss. ctrl",
S2:"Sample tune",
S3:"Vibrato LFO",
S4:"Tremolo LFO",
S8:"Channel pan",
@@ -629,18 +629,20 @@ function drawVoiceDetail() {
const effop = ptnDat[5]
const effarg = ptnDat[6] | (ptnDat[7] << 8)
// TODO draw cumulative internal status in the very time play cursor is on
con.move(6,1)
print(`Pitch $${note.hex04()}\tInst $${inst.hex02()}\tVolEff ${voleffop}.$${voleffarg.hex02()}\t`+
`PanEff ${paneffop}.$${paneffarg.hex02()}`)
con.move(7,1)
let fx = effop.toString(36).toUpperCase()
if (fx == '0') {
print(`Fx`+' '.repeat(32))
print(`\u00F8`+' '.repeat(32))
}
else {
if (fx == 'S') fx += (effarg >>> 12).hex1()
let fxName = fxNames[fx]
print(`Fx ${fxName} $${effarg.hex04()} `)
print(`\u00F8 ${fxName}\t$${effarg.hex04()} `)
}
}

Binary file not shown.

View File

@@ -219,8 +219,8 @@ function captureTrackerDataToFile(outFile) {
numPats & 0xFF, (numPats >>> 8) & 0xFF, // numPatterns Uint16 LE
bpmStored, // BPM with 24 bias
tickRate, // initial tick-rate
0x00,0x4C, // basenote (0x4C00 -- A3)
0x00,0x00,0xDC,0x43, // basefreq (440 Hz)
0x00,0x90, // basenote (0x9000 -- C8)
0x00,0xAC,0x02,0x46, // basefreq (8363 Hz)
0, // padding
]

View File

@@ -17,8 +17,9 @@ Effect support:
table" and "ScreamTracker 3 conversion notes". ST3 shared-memory recalls
(D/E/F/I/J/K/L/Q/R/S with $00 arg) are eagerly resolved per channel.
Cxx is BCD-decoded. K/L are split into H $0000 / G $0000 + volume-column
slide. M/N/X/P fold into volume / pan columns. W (global vol slide) and
Y (panbrello) are dropped with a -v warning.
slide. M/N/X/P fold into volume / pan columns. W (global vol slide) is
dropped with a -v warning. X converts to pan column. Y (panbrello) converts
to Taud Y. S5 selects the panbrello LFO waveform.
"""
import argparse
@@ -116,6 +117,7 @@ TOP_S = 0x1C # sub-effects
TOP_T = 0x1D # tempo set/slide
TOP_U = 0x1E # fine vibrato
TOP_V = 0x1F # global volume
TOP_Y = 0x22 # panbrello
# Volume / pan column selectors (2-bit field, packed into top of vol/pan byte).
SEL_SET = 0 # 6-bit value: set vol / pan
@@ -442,10 +444,13 @@ def encode_effect(cmd: int, arg: int, ch: int = 0, row: int = 0) -> tuple:
val = arg & 0xF
if sub in (0x1, 0x2, 0x3, 0x4, 0xB, 0xC, 0xD, 0xE, 0xF):
return (TOP_S, (sub << 12) | (val << 8), None, None)
if sub == 0x5:
# Panbrello LFO waveform — maps directly to Taud S$5x00.
return (TOP_S, 0x5000 | (val << 8), None, None)
if sub == 0x8:
# Coarse pan: nibble-repeat into Taud's S $80xx full-8-bit pan.
return (TOP_S, 0x8000 | (val * 0x11), None, None)
# S0/S5/S6/S7/S9/SA: filter, NNA, sound-control, stereo — drop silently.
# S0/S6/S7/S9/SA: filter, NNA, sound-control, stereo — drop silently.
return (TOP_NONE, 0, None, None)
if cmd == EFF_T:
@@ -465,8 +470,9 @@ def encode_effect(cmd: int, arg: int, ch: int = 0, row: int = 0) -> tuple:
return (TOP_NONE, 0, None, (SEL_SET, min(arg >> 2, 0x3F)))
if cmd == EFF_Y:
vprint(f" dropped Y{arg:02X} (panbrello) at ch{ch} row{row}")
return (TOP_NONE, 0, None, None)
hi = (arg >> 4) & 0xF
lo = arg & 0xF
return (TOP_Y, ((hi * 0x11) << 8) | (lo * 0x11), None, None)
if cmd == EFF_Z:
return (TOP_NONE, 0, None, None)
@@ -904,7 +910,7 @@ def assemble_taud(h: S3MHeader, instruments: list, patterns: list) -> bytes:
num_taud_pats_hi,
bpm_stored,
speed,
) + b'\x00\x4C' + b'\x00\x00\xDC\x43' + b'\x00'
) + b'\x00\x90' + b'\x00\xAC\xD02\x46' + b'\x00'
assert len(song_table) == TAUD_SONG_ENTRY
# Cue sheet (using remapped pattern indices)

View File

@@ -2211,16 +2211,21 @@ Endianness: Little
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 Tickrate (0 is invalid)
Uint16 Current Tuning base note (1..65533). A3 (the default value) is 0x4C00. If zero, assume the default value
Float32 Frequency at the base note. Default (A440) is 440.0. If zero, assume the default value
Uint16 Current Tuning base note (1..65533). A3 (western default) is 0x4C00. C8 (tracker default) is 0x9000. If zero, assume the tracker default value
Float32 Frequency at the base note. Tracker default is 8363.0. If zero, assume the tracker default
Byte[1] Reserved for future versions
Taud device can queue up to 2 "playdata" in its buffer, which can be interpreted as a song.
* Known standard tunings
A440. ISO standard. Tracker default
A440. ISO standard
A435. Former French standard (year 1859)
A452. Old Philharmonic pitch (19th century Britain)
C256. Power of two
C311. East Asian tuning (ROK National Gugak Center standard)
C262. Modern Chinese a-ak tuning convention
C311. Korean hyang-ak tuning standard (ROK National Gugak Center)
For your reference, tracker default tuning at A3 is 439.526 Hz (8363*2^(3/4) / 32)
## Pattern Bin and Cue Sheet
Raw Pattern Bin/Cue Sheet images

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB