From 6d70960e5c9451aea2a2de911bd27e8e18cac415 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Fri, 24 Apr 2026 09:21:10 +0900 Subject: [PATCH] Panbrello is 'Y' not 'W', oops --- TAUD_NOTE_EFFECTS.md | 22 ++++++++-------- .../torvald/tsvm/peripheral/AudioAdapter.kt | 26 ++++++++++--------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/TAUD_NOTE_EFFECTS.md b/TAUD_NOTE_EFFECTS.md index 8e099c6..bbf9402 100644 --- a/TAUD_NOTE_EFFECTS.md +++ b/TAUD_NOTE_EFFECTS.md @@ -493,27 +493,27 @@ A tempo slide's memory slot is separate from the set-tempo path and is private t --- -## W $xxyy — Panbrello (panning vibrato) with speed $xx and depth $yy +## Y $xxyy — Panbrello (panning vibrato) with speed $xx and depth $yy -**Plain.** Modulates panning with an LFO, symmetrically with H's pitch modulation. `$xx` is LFO speed, `$yy` depth; the waveform is selected by S $4x. +**Plain.** Modulates panning with an LFO, symmetrically with H's pitch modulation. `$xx` is LFO speed, `$yy` depth; the waveform is selected by S $5x. -**Compatibility.** IT `Wxy` uses nibbles; convert by nibble-repeat. IT's volume cap is $40; Taud's is $3F — very deep vibrato that would have briefly clipped at $40 in IT may clip slightly earlier in Taud. W has its own memory slot. +**Compatibility.** IT `Yxy` uses nibbles; convert by nibble-repeat. IT's panning cap is $40; Taud's is $3F — very deep vibrato that would have briefly clipped at $40 in IT may clip slightly earlier in Taud. Y has its own memory slot. **Implementation.** Identical machinery to H with a larger shift to fit the narrower volume range: ``` -on row parse (W): - if (arg >> 8) != 0: memory_W.speed = arg >> 8 - if (arg & $FF) != 0: memory_W.depth = arg & $FF +on row parse (Y): + if (arg >> 8) != 0: memory_Y.speed = arg >> 8 + if (arg & $FF) != 0: memory_Y.depth = arg & $FF on every tick (including tick 0): sine = ModSinusTable[(lfo_pos >> 2) & $3F] - vol_delta = (sine × memory_W.depth) >> 9 + vol_delta = (sine × memory_Y.depth) >> 9 applied_vol = clamp(base_vol + vol_delta, 0, $3F) - lfo_pos = (lfo_pos + memory_W.speed × 4) & $FF + lfo_pos = (lfo_pos + memory_Y.speed × 4) & $FF ``` -Peak at maximum settings: $7F × $FF >> 9 = $3F — the full panning range. Retrigger behaviour tracks the S $4x waveform nibble bit 2: cleared means retrigger on new note, set means preserve LFO position. +Peak at maximum settings: $7F × $FF >> 9 = $3F — the full panning range. Retrigger behaviour tracks the S $5x waveform nibble bit 2: cleared means retrigger on new note, set means preserve LFO position. --- @@ -595,11 +595,11 @@ ProTracker `E5x` maps to Taud `S $2x00` with the same index meaning. ## S $5x00 — Panbrello LFO waveform -**Plain.** Selects the shape of the panbrello (W) oscillator; value encoding is identical to S $3x. +**Plain.** Selects the shape of the panbrello (Y) oscillator; value encoding is identical to S $3x. **Compatibility.** IT `S5x` maps directly. -**Implementation.** As for S $3x, but applied to W's separate state (`panbrello_waveform`, `panbrello_retrigger`, and panbrello `lfo_pos`). +**Implementation.** As for S $3x, but applied to Y's separate state (`panbrello_waveform`, `panbrello_retrigger`, and panbrello `lfo_pos`). --- diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt index c2e5c2d..3714d8a 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/AudioAdapter.kt @@ -10,7 +10,6 @@ import net.torvald.UnsafePtr import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUint import net.torvald.tsvm.ThreeFiveMiniUfloat import net.torvald.tsvm.VM -import net.torvald.tsvm.getHashStr import net.torvald.tsvm.toInt import java.io.ByteArrayInputStream import kotlin.math.pow @@ -1089,7 +1088,7 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) { // K=0x14 K, L=0x15 L, O=0x18 sample offset, // Q=0x1A retrig, R=0x1B tremolo, S=0x1C subcommands, // T=0x1D tempo, U=0x1E fine vibrato, V=0x1F global vol, - // W=0x20 panbrello). + // Y=0x22 panbrello). // K (0x14) and L (0x15) are intentionally no-op in the engine — the // converter is required to split them into a recall-only H/G plus a // volume-column slide cell. @@ -1154,6 +1153,9 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) { const val OP_U = 0x1E const val OP_V = 0x1F const val OP_W = 0x20 + const val OP_X = 0x21 + const val OP_Y = 0x22 + const val OP_Z = 0x23 } private fun computePlaybackRate(inst: TaudInst, noteVal: Int): Double = @@ -1475,11 +1477,11 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) { val hi = (rawArg ushr 8) and 0xFF playhead.globalVolume = hi } - EffectOp.OP_W -> { + EffectOp.OP_Y -> { val sp = (rawArg ushr 8) and 0xFF val dp = rawArg and 0xFF - if (sp != 0) voice.mem.wSpeed = sp - if (dp != 0) voice.mem.wDepth = dp + if (sp != 0) voice.mem.ySpeed = sp + if (dp != 0) voice.mem.yDepth = dp voice.panbrelloActive = true } } @@ -1621,12 +1623,12 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) { voice.tremoloLfoPos = (voice.tremoloLfoPos + voice.mem.rSpeed * 4) and 0xFF } - // Panbrello (W) — modulates panning around base. + // Panbrello (Y) — modulates panning around base. if (voice.panbrelloActive) { val sine = lfoSample(voice.panbrelloLfoPos, voice.panbrelloWave) - val panDelta = (sine * voice.mem.wDepth) shr 9 + val panDelta = (sine * voice.mem.yDepth) shr 9 voice.rowPan = ((voice.channelPan ushr 2) + panDelta).coerceIn(0, 0x3F) - voice.panbrelloLfoPos = (voice.panbrelloLfoPos + voice.mem.wSpeed * 4) and 0xFF + voice.panbrelloLfoPos = (voice.panbrelloLfoPos + voice.mem.ySpeed * 4) and 0xFF } // Arpeggio (J) — overrides pitchToMixer for this tick (overlay on basePitch). @@ -1866,9 +1868,9 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) { // R (tremolo) — private speed and depth. var rSpeed: Int = 0 var rDepth: Int = 0 - // W (panbrello) — private speed and depth. - var wSpeed: Int = 0 - var wDepth: Int = 0 + // Y (panbrello) — private speed and depth. + var ySpeed: Int = 0 + var yDepth: Int = 0 // Private slots var d: Int = 0 var i: Int = 0 @@ -1930,7 +1932,7 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) { var tremoloWave = 0 var tremoloRetrig = true - // Panbrello (W) — uses memW. + // Panbrello (Y) — uses memY. var panbrelloActive = false var panbrelloLfoPos = 0 var panbrelloWave = 0