mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-06 13:38:30 +09:00
instrument volume fadeout
This commit is contained in:
@@ -864,9 +864,9 @@ Effects in this section modifies the behaviour of the mixer. Primary intention o
|
|||||||
|
|
||||||
## 1 $xx00 — Global behaviour flags
|
## 1 $xx00 — Global behaviour flags
|
||||||
|
|
||||||
**Plain.** Sets how the mixer should treat the panning. Available flags are:
|
**Plain.** Sets mixer-wide behaviour flags. Available flags are:
|
||||||
|
|
||||||
0b 0000 00fp
|
0b 0000 0mfp
|
||||||
|
|
||||||
- p unset: Linear panning mode (tracker-accurate). Centre panning gets 3 dB boost. Default setting.
|
- p unset: Linear panning mode (tracker-accurate). Centre panning gets 3 dB boost. Default setting.
|
||||||
- p set: Equal-power panning mode. L/R amplitude is at 0.707 when centre-panned.
|
- p set: Equal-power panning mode. L/R amplitude is at 0.707 when centre-panned.
|
||||||
@@ -874,6 +874,9 @@ Effects in this section modifies the behaviour of the mixer. Primary intention o
|
|||||||
- f unset: Linear tone mode. Pitch shift will behave like MIDI/ImpulseTracker/ScreamTracker linear mode. **Coarse and fine E/F arguments are stored as 4096-TET pitch units** and subtracted/added directly from the stored pitch.
|
- f unset: Linear tone mode. Pitch shift will behave like MIDI/ImpulseTracker/ScreamTracker linear mode. **Coarse and fine E/F arguments are stored as 4096-TET pitch units** and subtracted/added directly from the stored pitch.
|
||||||
- f set: Amiga (cycle-based) tone mode. Pitch shift will behave like ProTracker/ScreamTracker default mode. **Coarse and fine E/F arguments are stored as raw tracker period units** (the unscaled byte/nibble from the source PT/S3M/IT file) and applied in Amiga period space. Tone portamento (G) remains linear regardless of mode.
|
- f set: Amiga (cycle-based) tone mode. Pitch shift will behave like ProTracker/ScreamTracker default mode. **Coarse and fine E/F arguments are stored as raw tracker period units** (the unscaled byte/nibble from the source PT/S3M/IT file) and applied in Amiga period space. Tone portamento (G) remains linear regardless of mode.
|
||||||
|
|
||||||
|
- m unset: IT fadeout-zero policy. An instrument with stored volume fadeout = 0 does **not** fade out on key-off; the voice plays through until the volume envelope ends it (or never, if there is no envelope).
|
||||||
|
- m set: FT2 fadeout-zero policy. An instrument with stored volume fadeout = 0 is **cut** on the first tick after key-off (or NNA Note-Fade). Nonzero fadeouts behave identically in both modes — the per-tick decrement is always `fadeout / 65536` in unity-volume units.
|
||||||
|
|
||||||
**Implementation.**
|
**Implementation.**
|
||||||
- Panning-linear:
|
- Panning-linear:
|
||||||
- L_gain = if (pan < 0x80) 1.0 else 1.0 - (pan - 128.0) / 128.0
|
- L_gain = if (pan < 0x80) 1.0 else 1.0 - (pan - 128.0) / 128.0
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ class ITInstrument:
|
|||||||
# *_env_sustain: int (16-bit, 0b 0ut sssss pcb eeeee), 0 = no envelope
|
# *_env_sustain: int (16-bit, 0b 0ut sssss pcb eeeee), 0 = no envelope
|
||||||
# pf_is_filter: bool — pf envelope mode (False = pitch, True = filter)
|
# pf_is_filter: bool — pf envelope mode (False = pitch, True = filter)
|
||||||
# ifc / ifr : initial filter cutoff / resonance (0..127, 0 if not set)
|
# ifc / ifr : initial filter cutoff / resonance (0..127, 0 if not set)
|
||||||
# fadeout : 0..1024 (IT FadeOut field, applied per tick after key-off)
|
# fadeout : 0..1024 (IT FadeOut field; doubled to 0..2048 when written to Taud's 12-bit field)
|
||||||
# pps / ppc : pitch-pan separation (signed -32..+32) and centre note (0..119)
|
# pps / ppc : pitch-pan separation (signed -32..+32) and centre note (0..119)
|
||||||
# rv / rp : random volume swing (0..100) / random pan swing (0..64)
|
# rv / rp : random volume swing (0..100) / random pan swing (0..64)
|
||||||
# nna : new note action (IT 0=cut, 1=continue, 2=note off, 3=note fade)
|
# nna : new note action (IT 0=cut, 1=continue, 2=note off, 3=note fade)
|
||||||
@@ -1222,7 +1222,9 @@ def build_sample_inst_bin_it(samples_or_proxy: list,
|
|||||||
pan_sus = idata.get('pan_sus', 0)
|
pan_sus = idata.get('pan_sus', 0)
|
||||||
pf_sus = idata.get('pf_sus', 0)
|
pf_sus = idata.get('pf_sus', 0)
|
||||||
inst_gv = idata.get('inst_gv', 0xFF)
|
inst_gv = idata.get('inst_gv', 0xFF)
|
||||||
fadeout = idata.get('fadeout', 0) & 0x3FF # 10-bit (low 8 + high 2)
|
# IT fadeout (0..1024) is in half-units of Taud's per-tick scale; double to align with
|
||||||
|
# FT2 / native Taud (12-bit, engine subtracts fadeout/65536 per tick). Clamp defensively.
|
||||||
|
fadeout = min(0xFFF, (idata.get('fadeout', 0) & 0xFFFF) * 2)
|
||||||
|
|
||||||
struct.pack_into('<H', inst_bin, base + 15, vol_sus & 0xFFFF)
|
struct.pack_into('<H', inst_bin, base + 15, vol_sus & 0xFFFF)
|
||||||
struct.pack_into('<H', inst_bin, base + 17, pan_sus & 0xFFFF)
|
struct.pack_into('<H', inst_bin, base + 17, pan_sus & 0xFFFF)
|
||||||
@@ -1741,6 +1743,7 @@ def assemble_taud(h: ITHeader, samples: list, instruments: list,
|
|||||||
vprint(f" cue sheet: {len(sheet)} → {len(cue_comp)} bytes (gzip)")
|
vprint(f" cue sheet: {len(sheet)} → {len(cue_comp)} bytes (gzip)")
|
||||||
|
|
||||||
# flags byte: bit 1 (f) = Amiga pitch-slide mode (IT linear_slides flag inverted)
|
# flags byte: bit 1 (f) = Amiga pitch-slide mode (IT linear_slides flag inverted)
|
||||||
|
# bit 2 (m) cleared: IT fadeout-zero policy — stored fadeout=0 means "no fadeout".
|
||||||
flags_byte = 0x00 if h.linear_slides else 0x02
|
flags_byte = 0x00 if h.linear_slides else 0x02
|
||||||
# IT global/mix volumes are 0..128; rescale to Taud's 0..255 (clamped).
|
# IT global/mix volumes are 0..128; rescale to Taud's 0..255 (clamped).
|
||||||
global_vol_taud = min(0xFF, round(h.global_vol * 255 / 128))
|
global_vol_taud = min(0xFF, round(h.global_vol * 255 / 128))
|
||||||
|
|||||||
@@ -758,7 +758,9 @@ def assemble_taud(mod: dict) -> bytes:
|
|||||||
# ProTracker is Amiga-period-based by definition, so we set the f bit so
|
# ProTracker is Amiga-period-based by definition, so we set the f bit so
|
||||||
# the engine applies coarse pitch slides in period space (recovers PT's
|
# the engine applies coarse pitch slides in period space (recovers PT's
|
||||||
# characteristic non-linear pitch character).
|
# characteristic non-linear pitch character).
|
||||||
flags_byte = 0x02
|
# bit 2 (m) set: FT2 fadeout-zero policy — PT has no fadeout, so the stored
|
||||||
|
# zero on every instrument means "cut on key-off" (unified with S3M imports).
|
||||||
|
flags_byte = 0x02 | 0x04
|
||||||
song_table = encode_song_entry(
|
song_table = encode_song_entry(
|
||||||
song_offset=song_offset,
|
song_offset=song_offset,
|
||||||
num_voices=n_channels,
|
num_voices=n_channels,
|
||||||
|
|||||||
@@ -831,7 +831,9 @@ def assemble_taud(h: S3MHeader, instruments: list, patterns: list) -> bytes:
|
|||||||
|
|
||||||
# Song table row (32 bytes; see encode_song_entry).
|
# Song table row (32 bytes; see encode_song_entry).
|
||||||
# flags byte: bit 1 (f) = Amiga pitch-slide mode (mirrors the S3M linear_slides flag inverted)
|
# flags byte: bit 1 (f) = Amiga pitch-slide mode (mirrors the S3M linear_slides flag inverted)
|
||||||
flags_byte = 0x00 if h.linear_slides else 0x02
|
# bit 2 (m) set: FT2 fadeout-zero policy — S3M has no per-instrument fadeout field, so a
|
||||||
|
# stored zero means "cut on key-off" (matching ST3's lineage from the FT2 family).
|
||||||
|
flags_byte = (0x00 if h.linear_slides else 0x02) | 0x04
|
||||||
song_table = encode_song_entry(
|
song_table = encode_song_entry(
|
||||||
song_offset=song_offset,
|
song_offset=song_offset,
|
||||||
num_voices=C,
|
num_voices=C,
|
||||||
|
|||||||
@@ -2008,13 +2008,12 @@ Instrument bin: Registry for 256 instruments, formatted as:
|
|||||||
- IT: look for sample's SusLoop flag
|
- IT: look for sample's SusLoop flag
|
||||||
Bit16 Volume envelope sustain/loops and flags
|
Bit16 Volume envelope sustain/loops and flags
|
||||||
* Sustain is implemented by enabling 't' flag. FastTracker has no 'Sus Loop' but only 'Sus Point'; use same value for start and end index
|
* Sustain is implemented by enabling 't' flag. FastTracker has no 'Sus Loop' but only 'Sus Point'; use same value for start and end index
|
||||||
0b 0ut sssss pcb eeeee
|
0b 0ut sssss 0cb eeeee
|
||||||
s: sustain/loop start index
|
s: sustain/loop start index
|
||||||
e: sustain/loop end index
|
e: sustain/loop end index
|
||||||
|
|
||||||
b: use envelope
|
b: use envelope
|
||||||
c: envelope carry
|
c: envelope carry
|
||||||
p: (IT) fadeout is zero; (XM) fadeout is cut
|
|
||||||
|
|
||||||
t: the loop must sustain (key-off escapes the loop)
|
t: the loop must sustain (key-off escapes the loop)
|
||||||
u: set to enable the sustain/loop
|
u: set to enable the sustain/loop
|
||||||
@@ -2055,10 +2054,18 @@ Instrument bin: Registry for 256 instruments, formatted as:
|
|||||||
* ImpulseTracker has range of 0..128; multiply by (255/128) then round to int
|
* ImpulseTracker has range of 0..128; multiply by (255/128) then round to int
|
||||||
- ImpulseTracker also has samplewise default volume (0..64) and samplewise global volume (0..64), and they must be taken into account because Taud has no samplewise config, following the ImpulseTracker spec
|
- ImpulseTracker also has samplewise default volume (0..64) and samplewise global volume (0..64), and they must be taken into account because Taud has no samplewise config, following the ImpulseTracker spec
|
||||||
* FastTracker2 has range of 0..64; multiply by (255/64) then round to int
|
* FastTracker2 has range of 0..64; multiply by (255/64) then round to int
|
||||||
Uint8 Volume Fadeout low bits (IT: 1..256; XM: 0..255)
|
Uint8 Volume Fadeout low bits
|
||||||
Bit8 Fadeout and vibrato
|
Bit8 Fadeout and vibrato
|
||||||
0b 0000 ffff
|
0b 0000 ffff
|
||||||
f: Volume Fadeout high bits
|
f: Volume Fadeout high bits
|
||||||
|
* Combined 12-bit fadeout value is the engine's per-tick decrement, in 1/65536 units
|
||||||
|
(a unity-volume voice silenced over (65536 / fadeout) ticks after key-off).
|
||||||
|
* Stored 0: behaviour depends on Global Behaviour bit 'm' (see Song Table) —
|
||||||
|
IT mode (m=0) leaves the voice unfaded; FT2 mode (m=1) cuts on key-off.
|
||||||
|
* Source-format mapping:
|
||||||
|
- IT: stored fadeout (0..1024) MUST be doubled on import (taud = it × 2);
|
||||||
|
Taud's per-tick scale matches FT2 natively, so IT values are scaled to match.
|
||||||
|
- FT2: stored fadeout (0..0xFFF) is passed through unchanged.
|
||||||
Uint8 Volume swing (0..255 full range)
|
Uint8 Volume swing (0..255 full range)
|
||||||
Uint8 Vibrato speed
|
Uint8 Vibrato speed
|
||||||
* ImpulseTracker has samplewise vibrato speed (0..64), and they must be taken into account because Taud has no samplewise config
|
* ImpulseTracker has samplewise vibrato speed (0..64), and they must be taken into account because Taud has no samplewise config
|
||||||
@@ -2073,7 +2080,7 @@ Instrument bin: Registry for 256 instruments, formatted as:
|
|||||||
Uint8 Pan swing (0..255 full range)
|
Uint8 Pan swing (0..255 full range)
|
||||||
Uint8 Default cutoff (0..254 full range, 255 to off (-1 on IT). Effect range equals to that of ImpulseTracker -- 127 in IT is equal to 254 in Taud)
|
Uint8 Default cutoff (0..254 full range, 255 to off (-1 on IT). Effect range equals to that of ImpulseTracker -- 127 in IT is equal to 254 in Taud)
|
||||||
Uint8 Default resonance (0..254 full range, 255 to off (-1 on IT). Effect range equals to that of ImpulseTracker -- 127 in IT is equal to 254 in Taud)
|
Uint8 Default resonance (0..254 full range, 255 to off (-1 on IT). Effect range equals to that of ImpulseTracker -- 127 in IT is equal to 254 in Taud)
|
||||||
Uint16 Sample detune (in 4096-TET unit) (XM finetune scale need to be rescaled accordingly)
|
Uint16 Sample detune (in 4096-TET unit) (FT2 finetune scale need to be rescaled accordingly)
|
||||||
Bit8 Instrument Flag
|
Bit8 Instrument Flag
|
||||||
0b 000 www nn
|
0b 000 www nn
|
||||||
n: New note action. 00: note off, 01: note cut, 10: continue, 11: note fade (arranged differently to IT)
|
n: New note action. 00: note off, 01: note cut, 10: continue, 11: note fade (arranged differently to IT)
|
||||||
@@ -2098,7 +2105,7 @@ TODO:
|
|||||||
[x] implement sample loop sustain
|
[x] implement sample loop sustain
|
||||||
"Caveat: on a foreground voice, key-off (row.note == 0x0000) currently sets voice.active = false at AudioAdapter.kt:1713, which silences the channel immediately. Sustain-loop escape therefore only takes effect on background voices spawned by NNA "Note Off" — which matches the IT idiom of layering a new note over a sustained one. Let me know if you also want the foreground key-off to keep the voice playing through fadeout."
|
"Caveat: on a foreground voice, key-off (row.note == 0x0000) currently sets voice.active = false at AudioAdapter.kt:1713, which silences the channel immediately. Sustain-loop escape therefore only takes effect on background voices spawned by NNA "Note Off" — which matches the IT idiom of layering a new note over a sustained one. Let me know if you also want the foreground key-off to keep the voice playing through fadeout."
|
||||||
[x] cue and pattern compression of the Taud format (taud_common.py, taud.mjs)
|
[x] cue and pattern compression of the Taud format (taud_common.py, taud.mjs)
|
||||||
[ ] figure out how IT (8 bits) and FT2 (12 bits) handles volume fadeout numbers, and come up with a compatible Taud spec, then implement
|
[x] figure out how IT (0..256) and FT2 (0..FFF + cut) handles volume fadeout numbers, and come up with a compatible Taud spec, then implement
|
||||||
[ ] implement bitcrusher (eff sym '8')
|
[ ] implement bitcrusher (eff sym '8')
|
||||||
|
|
||||||
|
|
||||||
@@ -2314,6 +2321,11 @@ Endianness: Little
|
|||||||
Uint16 Current Tuning base note (1..65533). A4 (western default) is 0x5C00. C9 (tracker default) is 0xA000. If zero, assume the tracker default value
|
Uint16 Current Tuning base note (1..65533). A4 (western default) is 0x5C00. C9 (tracker default) is 0xA000. If zero, assume the tracker default value
|
||||||
Float32 Frequency at the base note. Tracker default is 8363.0. If zero, assume the tracker default
|
Float32 Frequency at the base note. Tracker default is 8363.0. If zero, assume the tracker default
|
||||||
Uint8 Flags for Global Behaviour (effect symbol '1')
|
Uint8 Flags for Global Behaviour (effect symbol '1')
|
||||||
|
0b 0000 0mfp
|
||||||
|
p: panning law (0=linear, 1=equal-power)
|
||||||
|
f: tone mode (0=linear pitch slides, 1=Amiga period slides)
|
||||||
|
m: fadeout-zero policy (0=IT — stored fadeout 0 means no fadeout;
|
||||||
|
1=FT2 — stored fadeout 0 means cut on key-off)
|
||||||
Uint8 Song global volume
|
Uint8 Song global volume
|
||||||
* ImpulseTracker has range of 0..128; multiply by (255/128) then round to int
|
* ImpulseTracker has range of 0..128; multiply by (255/128) then round to int
|
||||||
Uint8 Song mixing volume
|
Uint8 Song mixing volume
|
||||||
|
|||||||
@@ -1754,9 +1754,11 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
// 1 $xx00 — Global behaviour flags byte in the high byte (see TAUD_NOTE_EFFECTS.md §1).
|
// 1 $xx00 — Global behaviour flags byte in the high byte (see TAUD_NOTE_EFFECTS.md §1).
|
||||||
// bit 0 (p): 0=linear pan, 1=equal-power pan
|
// bit 0 (p): 0=linear pan, 1=equal-power pan
|
||||||
// bit 1 (f): 0=linear pitch slides, 1=Amiga-mode pitch slides
|
// bit 1 (f): 0=linear pitch slides, 1=Amiga-mode pitch slides
|
||||||
|
// bit 2 (m): fadeout-zero policy. 0=IT (stored 0 ⇒ no fadeout), 1=FT2 (stored 0 ⇒ cut on key-off)
|
||||||
val flags = rawArg ushr 8
|
val flags = rawArg ushr 8
|
||||||
ts.panLaw = flags and 1
|
ts.panLaw = flags and 1
|
||||||
ts.amigaMode = (flags and 2) != 0
|
ts.amigaMode = (flags and 2) != 0
|
||||||
|
ts.fadeoutCutOnZero = (flags and 4) != 0
|
||||||
}
|
}
|
||||||
EffectOp.OP_A -> {
|
EffectOp.OP_A -> {
|
||||||
val tr = (rawArg ushr 8) and 0xFF
|
val tr = (rawArg ushr 8) and 0xFF
|
||||||
@@ -2141,12 +2143,16 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
// Refresh biquad filter coefficients once per tick (only recomputes when changed).
|
// Refresh biquad filter coefficients once per tick (only recomputes when changed).
|
||||||
refreshVoiceFilter(voice)
|
refreshVoiceFilter(voice)
|
||||||
|
|
||||||
// Volume fadeout: after key-off OR Note-Fade NNA, decrement by inst.volumeFadeout / 1024 per tick.
|
// Volume fadeout: after key-off OR Note-Fade NNA, decrement by inst.volumeFadeout / 65536 per tick.
|
||||||
// The 10-bit fadeout value is split across volumeFadeoutLow + low nibble of fadeoutHigh.
|
// The 12-bit fadeout value is split across volumeFadeoutLow + low nibble of fadeoutHigh.
|
||||||
|
// Stored 0: with fadeoutCutOnZero (FT2 mode) the voice is cut on key-off; otherwise no fadeout (IT mode).
|
||||||
if (voice.keyOff || voice.noteFading) {
|
if (voice.keyOff || voice.noteFading) {
|
||||||
val fadeStep = inst.volumeFadeoutLow or ((inst.fadeoutHigh and 0x0F) shl 8)
|
val fadeStep = inst.volumeFadeoutLow or ((inst.fadeoutHigh and 0x0F) shl 8)
|
||||||
if (fadeStep > 0) {
|
if (fadeStep > 0) {
|
||||||
voice.fadeoutVolume = (voice.fadeoutVolume - fadeStep / 1024.0).coerceAtLeast(0.0)
|
voice.fadeoutVolume = (voice.fadeoutVolume - fadeStep / 65536.0).coerceAtLeast(0.0)
|
||||||
|
if (voice.fadeoutVolume <= 0.0) voice.active = false
|
||||||
|
} else if (ts.fadeoutCutOnZero) {
|
||||||
|
voice.active = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2198,7 +2204,11 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
if (bg.keyOff || bg.noteFading) {
|
if (bg.keyOff || bg.noteFading) {
|
||||||
val fadeStep = inst.volumeFadeoutLow or ((inst.fadeoutHigh and 0x0F) shl 8)
|
val fadeStep = inst.volumeFadeoutLow or ((inst.fadeoutHigh and 0x0F) shl 8)
|
||||||
if (fadeStep > 0) {
|
if (fadeStep > 0) {
|
||||||
bg.fadeoutVolume = (bg.fadeoutVolume - fadeStep / 1024.0).coerceAtLeast(0.0)
|
bg.fadeoutVolume = (bg.fadeoutVolume - fadeStep / 65536.0).coerceAtLeast(0.0)
|
||||||
|
} else if (ts.fadeoutCutOnZero) {
|
||||||
|
bg.active = false
|
||||||
|
bgIt.remove()
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Auto-vibrato keeps running on backgrounds — it's an instrument-intrinsic LFO.
|
// Auto-vibrato keeps running on backgrounds — it's an instrument-intrinsic LFO.
|
||||||
@@ -2662,6 +2672,7 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
// Global mixer config (effect 1).
|
// Global mixer config (effect 1).
|
||||||
var panLaw = 0 // 0 = linear balance (default), 1 = equal-power
|
var panLaw = 0 // 0 = linear balance (default), 1 = equal-power
|
||||||
var amigaMode = false // false = linear pitch slides, true = Amiga period-space slides
|
var amigaMode = false // false = linear pitch slides, true = Amiga period-space slides
|
||||||
|
var fadeoutCutOnZero = false // false = IT (stored 0 ⇒ no fadeout); true = FT2 (stored 0 ⇒ cut on key-off)
|
||||||
|
|
||||||
// Pending row-end events (set during a row by B/C; consumed at row end).
|
// Pending row-end events (set during a row by B/C; consumed at row end).
|
||||||
var pendingOrderJump = -1 // -1 = none; otherwise the order index to jump to
|
var pendingOrderJump = -1 // -1 = none; otherwise the order index to jump to
|
||||||
@@ -2772,7 +2783,11 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
} }
|
} }
|
||||||
7 -> if (isPcmMode) { pcmUpload = true } else {
|
7 -> if (isPcmMode) { pcmUpload = true } else {
|
||||||
initialGlobalFlags = byte
|
initialGlobalFlags = byte
|
||||||
trackerState?.let { ts -> ts.panLaw = byte and 1; ts.amigaMode = (byte and 2) != 0 }
|
trackerState?.let { ts ->
|
||||||
|
ts.panLaw = byte and 1
|
||||||
|
ts.amigaMode = (byte and 2) != 0
|
||||||
|
ts.fadeoutCutOnZero = (byte and 4) != 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
8 -> { bpm = byte + 24 }
|
8 -> { bpm = byte + 24 }
|
||||||
9 -> { tickRate = byte }
|
9 -> { tickRate = byte }
|
||||||
@@ -2807,6 +2822,7 @@ class AudioAdapter(val vm: VM) : PeriBase(VM.PERITYPE_SOUND) {
|
|||||||
ts.finePatternDelayExtra = 0
|
ts.finePatternDelayExtra = 0
|
||||||
ts.panLaw = initialGlobalFlags and 1
|
ts.panLaw = initialGlobalFlags and 1
|
||||||
ts.amigaMode = (initialGlobalFlags and 2) != 0
|
ts.amigaMode = (initialGlobalFlags and 2) != 0
|
||||||
|
ts.fadeoutCutOnZero = (initialGlobalFlags and 4) != 0
|
||||||
ts.voices.forEach {
|
ts.voices.forEach {
|
||||||
it.active = false
|
it.active = false
|
||||||
it.channelVolume = 0x3F
|
it.channelVolume = 0x3F
|
||||||
|
|||||||
Reference in New Issue
Block a user