mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-06 13:38:30 +09:00
s3m to taud fix (not emitting volcmd on note retrigger)
This commit is contained in:
20
s3m2taud.py
20
s3m2taud.py
@@ -660,7 +660,9 @@ def build_pattern(s3m_grid: list, ch_idx: int, default_pan: int,
|
|||||||
inst_vols = {}
|
inst_vols = {}
|
||||||
out = bytearray(PATTERN_BYTES)
|
out = bytearray(PATTERN_BYTES)
|
||||||
rows = s3m_grid[ch_idx] if ch_idx < len(s3m_grid) else [S3MRow()] * PATTERN_ROWS
|
rows = s3m_grid[ch_idx] if ch_idx < len(s3m_grid) else [S3MRow()] * PATTERN_ROWS
|
||||||
last_inst = 0 # 1-based; tracks which instrument is loaded on this channel
|
last_inst = 0 # 1-based; tracks which instrument is loaded on this channel
|
||||||
|
last_note = S3M_NOTE_EMPTY # last raw S3M note byte that was a real pitch
|
||||||
|
last_vol = None # last SEL_SET volume value (0-63), for retrigger recall
|
||||||
for r, row in enumerate(rows[:PATTERN_ROWS]):
|
for r, row in enumerate(rows[:PATTERN_ROWS]):
|
||||||
note = encode_note(row.note)
|
note = encode_note(row.note)
|
||||||
inst = row.inst # S3M 1-based → Taud 1-based
|
inst = row.inst # S3M 1-based → Taud 1-based
|
||||||
@@ -668,6 +670,12 @@ def build_pattern(s3m_grid: list, ch_idx: int, default_pan: int,
|
|||||||
if row.inst > 0:
|
if row.inst > 0:
|
||||||
last_inst = row.inst
|
last_inst = row.inst
|
||||||
|
|
||||||
|
# ── Instrument-only retrigger ──
|
||||||
|
# Instrument-only row: recall the last volume without touching the note.
|
||||||
|
retrigger = (row.inst > 0
|
||||||
|
and row.note == S3M_NOTE_EMPTY
|
||||||
|
and last_note not in (S3M_NOTE_EMPTY, S3M_NOTE_OFF))
|
||||||
|
|
||||||
op, arg, vol_override, pan_override = encode_effect(
|
op, arg, vol_override, pan_override = encode_effect(
|
||||||
row.effect, row.effect_arg, ch_idx, r)
|
row.effect, row.effect_arg, ch_idx, r)
|
||||||
|
|
||||||
@@ -683,11 +691,21 @@ def build_pattern(s3m_grid: list, ch_idx: int, default_pan: int,
|
|||||||
# so prior channel-vol state doesn't bleed through.
|
# so prior channel-vol state doesn't bleed through.
|
||||||
vol_sel = SEL_SET
|
vol_sel = SEL_SET
|
||||||
vol_value = inst_vols.get(last_inst, 0x3F)
|
vol_value = inst_vols.get(last_inst, 0x3F)
|
||||||
|
elif retrigger and last_vol is not None:
|
||||||
|
# Instrument-only row: re-emit the last known volume so the sample
|
||||||
|
# restarts at the correct level without an explicit note trigger.
|
||||||
|
vol_sel, vol_value = SEL_SET, last_vol
|
||||||
elif vol_override is not None:
|
elif vol_override is not None:
|
||||||
vol_sel, vol_value = vol_override
|
vol_sel, vol_value = vol_override
|
||||||
else:
|
else:
|
||||||
vol_sel, vol_value = SEL_FINE, 0 # no-op fine slide
|
vol_sel, vol_value = SEL_FINE, 0 # no-op fine slide
|
||||||
|
|
||||||
|
# Track note and volume for future retrigger lookups.
|
||||||
|
if row.note not in (S3M_NOTE_EMPTY, S3M_NOTE_OFF):
|
||||||
|
last_note = row.note
|
||||||
|
if vol_sel == SEL_SET:
|
||||||
|
last_vol = vol_value
|
||||||
|
|
||||||
# ── Pan column ──
|
# ── Pan column ──
|
||||||
if pan_override is not None:
|
if pan_override is not None:
|
||||||
pan_sel, pan_value = pan_override
|
pan_sel, pan_value = pan_override
|
||||||
|
|||||||
@@ -2210,9 +2210,9 @@ Rows of 16 bytes:
|
|||||||
Uint16 Number of patterns (0 is invalid. pattern bin length = numPats * 8 bytes)
|
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 BPM (bias of -24. 0x00=24, 0xFF=279)
|
||||||
Uint8 Initial Tickrate (0 is invalid)
|
Uint8 Initial Tickrate (0 is invalid)
|
||||||
Uint16 Current Tuning base note (0-4095), assuming octave 3. C3 (the default value) is 0x4000
|
Uint16 Current Tuning base note (1-4094), assuming octave 3. C3 (the default value) is 0x4000. If zero, assume the default value
|
||||||
Float32 Frequency at the base note. Default (A440) is 261.6255653
|
Float32 Frequency at the base note. Default (A440) is 261.6255653. If zero, assume the default value
|
||||||
Byte[7] Reserved for future versions
|
Byte[1] Reserved for future versions
|
||||||
|
|
||||||
Taud device can queue up to 2 "playdata" in its buffer, which can be interpreted as a song.
|
Taud device can queue up to 2 "playdata" in its buffer, which can be interpreted as a song.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user