mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-12 15:44:05 +09:00
taud bugfix
This commit is contained in:
20
mod2taud.py
20
mod2taud.py
@@ -182,6 +182,26 @@ def parse_mod(data: bytes):
|
|||||||
inst = (b0 & 0xF0) | ((b2 >> 4) & 0x0F)
|
inst = (b0 & 0xF0) | ((b2 >> 4) & 0x0F)
|
||||||
effect = b2 & 0x0F
|
effect = b2 & 0x0F
|
||||||
arg = b3
|
arg = b3
|
||||||
|
# MT-style PT-strict cell rewrites (LoaderMOD.cpp:354-365):
|
||||||
|
# PT does not recall arg for portamento up/down (1xx, 2xx) or
|
||||||
|
# volume slide (Axx); the literal arg is read every tick. The
|
||||||
|
# vol-slide nibbles in 5xx/6xx likewise take literal args, with
|
||||||
|
# the recalled state living in the porta/vibrato side. So a
|
||||||
|
# zero-arg cell decays to a no-slide variant: 1/2/A drop to
|
||||||
|
# no-op, 5 collapses to bare tone-porta (3), 6 to bare vibrato
|
||||||
|
# (4). Without this, resolve_pt_recalls would back-fill these
|
||||||
|
# zero args from the cohort memory and produce a continuous
|
||||||
|
# slide where PT plays a single-row swell (canonical bug:
|
||||||
|
# GSLINGER ord 0x03 ch1 — `5 01` on r30/r38 with `5 00` on the
|
||||||
|
# rest, was fading 24→0 in 5 rows instead of stair-stepping
|
||||||
|
# 24→14 across 16 rows).
|
||||||
|
if arg == 0:
|
||||||
|
if effect in (0x1, 0x2, 0xA):
|
||||||
|
effect = 0x0
|
||||||
|
elif effect == 0x5:
|
||||||
|
effect = 0x3
|
||||||
|
elif effect == 0x6:
|
||||||
|
effect = 0x4
|
||||||
cell = grid[ch][r]
|
cell = grid[ch][r]
|
||||||
cell.period = period
|
cell.period = period
|
||||||
cell.inst = inst
|
cell.inst = inst
|
||||||
|
|||||||
@@ -2394,8 +2394,8 @@ TODO:
|
|||||||
when no V column is present. Engine + all four `*2taud` converters
|
when no V column is present. Engine + all four `*2taud` converters
|
||||||
updated; legacy `.taud` files (byte 196 == 0) fall back to the
|
updated; legacy `.taud` files (byte 196 == 0) fall back to the
|
||||||
previous "row volume default = 63" behaviour.
|
previous "row volume default = 63" behaviour.
|
||||||
[ ] Physical Presence order 0x1F chn 2: note cuts unexpectedly fast?
|
[x] physical_presence order 0x1F chn 2: note cuts unexpectedly fast — engine fix
|
||||||
GSLINGER order 0x03 chn 1: L 0100 fades unexpectedly fast?
|
[x] GSLINGER order 0x03 chn 1: L 0100 fades unexpectedly fast? — converter fix
|
||||||
|
|
||||||
TODO - list of demo songs that MUST ship with Microtone:
|
TODO - list of demo songs that MUST ship with Microtone:
|
||||||
* 4THSYM (rename to Fourth Symmetriad) — excellent piece for demonstrating NNAs and filter envelopes
|
* 4THSYM (rename to Fourth Symmetriad) — excellent piece for demonstrating NNAs and filter envelopes
|
||||||
|
|||||||
@@ -2145,11 +2145,28 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
// mirroring G's behaviour — the L command continues the porta started by an earlier G.
|
// mirroring G's behaviour — the L command continues the porta started by an earlier G.
|
||||||
val toneG = (row.effect == EffectOp.OP_G || row.effect == EffectOp.OP_L)
|
val toneG = (row.effect == EffectOp.OP_G || row.effect == EffectOp.OP_L)
|
||||||
when (row.note) {
|
when (row.note) {
|
||||||
// No note but an instrument byte is present: latch the instrument so
|
// No note but an instrument byte is present: latch the instrument and
|
||||||
// the *next* note-only trigger picks up the right sample. Trackers
|
// re-seed the channel volume from the new sample's Default Note Volume.
|
||||||
// call this an "instrument-only retrigger"; in MOD/S3M/IT the sample
|
// PT, FT2, IT and Schism all do this — pt2_replayer.c:1086 writes
|
||||||
// keeps playing, but the channel's instrument reference advances.
|
// ch->n_volume = s->volume on every sample-byte row regardless of note;
|
||||||
0xFFFF -> { if (row.instrment != 0) voice.instrumentId = row.instrment }
|
// ft2_replayer.c:1431-1434 calls resetVolumes(ch) when (note==0 && inst>0);
|
||||||
|
// schism csf_instrument_change writes chan->volume = psmp->volume whenever
|
||||||
|
// inst_column is set. Without this, a MOD pattern that runs continuous
|
||||||
|
// volume slides while re-asserting the sample byte each row (e.g.
|
||||||
|
// physical_presence ord 0x1F ch2: every row carries `... 1E A0F/A09/A02`)
|
||||||
|
// silences after the first row because the slide saturates at 0 and there's
|
||||||
|
// nothing to lift the volume back up before the next slide starts.
|
||||||
|
0xFFFF -> {
|
||||||
|
if (row.instrment != 0) {
|
||||||
|
voice.instrumentId = row.instrment
|
||||||
|
val seedVol = rowVolumeFromDefault(instruments[voice.instrumentId])
|
||||||
|
voice.channelVolume = seedVol
|
||||||
|
voice.rowVolume = seedVol
|
||||||
|
voice.keyOff = false
|
||||||
|
voice.noteFading = false
|
||||||
|
voice.fadeoutVolume = 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
// Key-off: release sustain; envelope walks past the sustain point and the fadeout
|
// Key-off: release sustain; envelope walks past the sustain point and the fadeout
|
||||||
// begins (foreground-voice fade path at line ~2380). The voice deactivates when
|
// begins (foreground-voice fade path at line ~2380). The voice deactivates when
|
||||||
// fadeoutVolume reaches 0, or immediately if FT2-mode fadeStep == 0. Setting
|
// fadeoutVolume reaches 0, or immediately if FT2-mode fadeStep == 0. Setting
|
||||||
|
|||||||
Reference in New Issue
Block a user