mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-06 05:28:31 +09:00
Compare commits
2 Commits
6d70960e5c
...
a1b62f3155
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1b62f3155 | ||
|
|
4802e10dfc |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -68,3 +68,5 @@ assets/disk0/*.mov
|
||||
assets/diskMediabin/*
|
||||
|
||||
video_encoder/*
|
||||
|
||||
assets/disk0/tvdos/bin/tautfont.png
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
]
|
||||
|
||||
|
||||
18
s3m2taud.py
18
s3m2taud.py
@@ -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)
|
||||
|
||||
@@ -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 |
Reference in New Issue
Block a user