Closed mooinglemur closed 1 year ago
I know this is @ZeroByteOrg 's contribution to Furnace. Unfortunately he hasn't been around the past few months, otherwise I'd pester him directly. :)
I have a feeling that this is intentional. Does this happen when loop is disabled?
This behavior is not seen when loop is off. I've tested outputs with a trivial loop to the beginning and also with the 0Bxx
effect. Both the trivial loop and the 0Bxx
effect result in the extra tick.
Here's a unified diff of the ymls based on a non-looped ZSM and a trivially-looped ZSM (same song). You can see that there's one extra delay tick at the very end. Right before the tick it appears to set up some state to make sure the registers are correct at the loop point, but it also seems to start 5 notes playing right before the delay of 1.
Those same five channels key on in the tick at the loop point, too, so it sounds like a stutter.
If I remove all the key-on events at the end, as well as the single-tick delay, the ZSM then sounds correct.
--- bob-noloop.yml 2023-06-11 16:39:46.223545750 -0400
+++ bob-loop.yml 2023-06-11 16:44:24.303145418 -0400
@@ -5,6 +5,14 @@
tick_rate: 60 # Number of ticks per second
reserved_header: 0x0000 # For future use
data:
+ - ym_write: # YM write block: 3 (0x03) events
+ - addr: 0x18 # LFO frequency
+ data: 0x00 # 0.000833 Hz
+ - addr: 0x19 # LFO amplitude
+ data: 0x7f # AMD: 127 (0x7f)
+ - addr: 0x19 # LFO amplitude
+ data: 0xff # PMD: 127 (0x7f)
+ - loop # Loop start: 0m00.0s at byte offset 23 (0x17)
- psg_write: # PSG write block: 4 (0x04) events
- addr: 0x08 # Channel 2 LSB of frequency
data: 0xdc # (partial change)
@@ -15,12 +23,6 @@
- addr: 0x0b # Channel 2 Waveform, Pulse width
data: 0xc0 # Noise
- ym_write: # YM write block: 63 (0x3f) events
- - addr: 0x18 # LFO frequency
- data: 0x00 # 0.000833 Hz
- - addr: 0x19 # LFO amplitude
- data: 0x7f # AMD: 127 (0x7f)
- - addr: 0x19 # LFO amplitude
- data: 0xff # PMD: 127 (0x7f)
- addr: 0x08 # Key Control
data: 0x00 # Key off, channel 0
- addr: 0x20 # Channel 0: R/L Output, Feedback, Algorithm (RL_FB_CON)
@@ -141,13 +143,13 @@
data: 0x3a # D1L: 3, Base Release Rate: 143.50 ms (0x0a)
- addr: 0x08 # Key Control
data: 0x79 # Key on, channel 1
- - ym_write: # YM write block: 63 (0x3f) events
- addr: 0x08 # Key Control
data: 0x02 # Key off, channel 2
- addr: 0x22 # Channel 2: R/L Output, Feedback, Algorithm (RL_FB_CON)
data: 0xda # Left+Right, Feedback 3, Algorithm 2
- addr: 0x2a # Channel 2: Key code (KC)
data: 0x0e # Note C-0
+ - ym_write: # YM write block: 63 (0x3f) events
- addr: 0x32 # Channel 2: Key fraction (KF)
data: 0x00 # +0.00 cents
- addr: 0x3a # Channel 2: Modulation Sensitivity (PMS_AMS)
@@ -268,13 +270,13 @@
data: 0x7a # Left, Feedback 7, Algorithm 2
- addr: 0x2c # Channel 4: Key code (KC)
data: 0x3e # Note C-3
- - ym_write: # YM write block: 27 (0x1b) events
- addr: 0x34 # Channel 4: Key fraction (KF)
data: 0x0c # +4.69 cents
- addr: 0x3c # Channel 4: Modulation Sensitivity (PMS_AMS)
data: 0x00 # PMS: 0, AMS: 0
- addr: 0x44 # Channel 4 op M1: Fine Detune, Multiplier (DT1_MUL)
data: 0x01 # DT1: 0, MUL: 1
+ - ym_write: # YM write block: 24 (0x18) events
- addr: 0x4c # Channel 4 op M2: Fine Detune, Multiplier (DT1_MUL)
data: 0x11 # DT1: 1, MUL: 1
- addr: 0x54 # Channel 4 op C1: Fine Detune, Multiplier (DT1_MUL)
@@ -25858,4 +25860,81 @@
- addr: 0x08 # Key Control
data: 0x04 # Key off, channel 4
- delay: 0x04 # 4 ticks (0.07s), total 4352 (1m12.53s)
- - eod # End of ZSM data
+ - psg_write: # PSG write block: 1 (0x01) events
+ - addr: 0x0a # Channel 2 R+L Output, Volume
+ data: 0xf8 # Left+Right, Volume 56 (0x38)
+ - ym_write: # YM write block: 36 (0x24) events
+ - addr: 0x21 # Channel 1: R/L Output, Feedback, Algorithm (RL_FB_CON)
+ data: 0xfa # Left+Right, Feedback 7, Algorithm 2
+ - addr: 0x41 # Channel 1 op M1: Fine Detune, Multiplier (DT1_MUL)
+ data: 0x01 # DT1: 0, MUL: 1
+ - addr: 0x49 # Channel 1 op M2: Fine Detune, Multiplier (DT1_MUL)
+ data: 0x11 # DT1: 1, MUL: 1
+ - addr: 0x51 # Channel 1 op C1: Fine Detune, Multiplier (DT1_MUL)
+ data: 0x01 # DT1: 0, MUL: 1
+ - addr: 0x59 # Channel 1 op C2: Fine Detune, Multiplier (DT1_MUL)
+ data: 0x01 # DT1: 0, MUL: 1
+ - addr: 0x61 # Channel 1 op M1: Volume Attenuation (TL)
+ data: 0x27 # Attenuation: -29.25 dB
+ - addr: 0x69 # Channel 1 op M2: Volume Attenuation (TL)
+ data: 0x21 # Attenuation: -24.75 dB
+ - addr: 0x71 # Channel 1 op C1: Volume Attenuation (TL)
+ data: 0x10 # Attenuation: -12.00 dB
+ - addr: 0x79 # Channel 1 op C2: Volume Attenuation (TL)
+ data: 0x09 # Attenuation: -6.75 dB
+ - addr: 0x81 # Channel 1 op M1: Key Scaling, Attack Rate (KS_AR)
+ data: 0x5c # KS: 1, Base Attack Rate: 0.97 ms
+ - addr: 0x89 # Channel 1 op M2: Key Scaling, Attack Rate (KS_AR)
+ data: 0x13 # KS: 0, Base Attack Rate: 20.76 ms
+ - addr: 0x91 # Channel 1 op C1: Key Scaling, Attack Rate (KS_AR)
+ data: 0x4f # KS: 1, Base Attack Rate: 83.06 ms
+ - addr: 0x99 # Channel 1 op C2: Key Scaling, Attack Rate (KS_AR)
+ data: 0x13 # KS: 0, Base Attack Rate: 20.76 ms
+ - addr: 0xa1 # Channel 1 op M1: AM Enable, Decay Rate 1 (AMSEN_D1R)
+ data: 0x08 # AM: disabled, Base D1 Rate: 13776.22 ms
+ - addr: 0xa9 # Channel 1 op M2: AM Enable, Decay Rate 1 (AMSEN_D1R)
+ data: 0x04 # AM: disabled, Base D1 Rate: 55104.87 ms
+ - addr: 0xb1 # Channel 1 op C1: AM Enable, Decay Rate 1 (AMSEN_D1R)
+ data: 0x08 # AM: disabled, Base D1 Rate: 13776.22 ms
+ - addr: 0xb9 # Channel 1 op C2: AM Enable, Decay Rate 1 (AMSEN_D1R)
+ data: 0x06 # AM: disabled, Base D1 Rate: 27552.43 ms
+ - addr: 0xc1 # Channel 1 op M1: Coarse Detune, Decay Rate 2 (DT2_D2R)
+ data: 0x00 # DT2: 0, Base D2 Rate: inf ms
+ - addr: 0xd1 # Channel 1 op C1: Coarse Detune, Decay Rate 2 (DT2_D2R)
+ data: 0x03 # DT2: 0, Base D2 Rate: 73473.16 ms
+ - addr: 0xe1 # Channel 1 op M1: Decay 1 Level, Release Rate (D1L_RR)
+ data: 0x03 # D1L: 0, Base Release Rate: 18368.29 ms (0x03)
+ - addr: 0xe9 # Channel 1 op M2: Decay 1 Level, Release Rate (D1L_RR)
+ data: 0x50 # D1L: 5, Base Release Rate: inf ms (0x00)
+ - addr: 0xf1 # Channel 1 op C1: Decay 1 Level, Release Rate (D1L_RR)
+ data: 0x44 # D1L: 4, Base Release Rate: 9184.14 ms (0x04)
+ - addr: 0xf9 # Channel 1 op C2: Decay 1 Level, Release Rate (D1L_RR)
+ data: 0x3a # D1L: 3, Base Release Rate: 143.50 ms (0x0a)
+ - addr: 0x08 # Key Control
+ data: 0x00 # Key off, channel 0
+ - addr: 0x08 # Key Control
+ data: 0x01 # Key off, channel 1
+ - addr: 0x08 # Key Control
+ data: 0x02 # Key off, channel 2
+ - addr: 0x08 # Key Control
+ data: 0x03 # Key off, channel 3
+ - addr: 0x08 # Key Control
+ data: 0x04 # Key off, channel 4
+ - addr: 0x28 # Channel 0: Key code (KC)
+ data: 0x2e # Note C-2
+ - addr: 0x08 # Key Control
+ data: 0x78 # Key on, channel 0
+ - addr: 0x29 # Channel 1: Key code (KC)
+ data: 0x4e # Note C-4
+ - addr: 0x08 # Key Control
+ data: 0x79 # Key on, channel 1
+ - addr: 0x08 # Key Control
+ data: 0x7a # Key on, channel 2
+ - addr: 0x2b # Channel 3: Key code (KC)
+ data: 0x4d # Note B-4
+ - addr: 0x08 # Key Control
+ data: 0x7b # Key on, channel 3
+ - addr: 0x08 # Key Control
+ data: 0x7c # Key on, channel 4
+ - delay: 0x01 # 1 ticks (0.02s), total 4353 (1m12.55s)
+ - eod # End of ZSM data
Ooh, here's an even more demonstrative example. This song does not have any note events at the loop point, only empty rows. Notice the extra tick in the looped version:
--- lul-noloop.yml 2023-06-11 17:17:45.138691420 -0400
+++ lul-loop.yml 2023-06-11 17:17:09.792601344 -0400
@@ -12,6 +12,7 @@
data: 0x7f # AMD: 127 (0x7f)
- addr: 0x19 # LFO amplitude
data: 0xff # PMD: 127 (0x7f)
+ - loop # Loop start: 0m00.0s at byte offset 23 (0x17)
- delay: 0x08 # 8 ticks (0.13s), total 8 (0m00.13s)
- ym_write: # YM write block: 60 (0x3c) events
- addr: 0x08 # Key Control
@@ -2912,5 +2913,5 @@
- ym_write: # YM write block: 1 (0x01) events
- addr: 0x08 # Key Control
data: 0x07 # Key off, channel 7
- - delay: 0x08 # 8 ticks (0.13s), total 3702 (1m01.70s)
- - eod # End of ZSM data
+ - delay: 0x09 # 9 ticks (0.15s), total 3703 (1m01.72s)
+ - eod # End of ZSM data
I tried to bisect to see if this behavior was introduced after ZSM support was first merged, but it appears that the bad behavior has existed as long as the feature has been in Furnace.
Fixed by #1191. Hoping it doesn't break things after loop (especially FM).
I have attached a simple test case. Exporting
looptest.fur
to ZSM ends up writing out a ZSM with an extra key event and a one-tick delay.looptest.fur.gz looptest.zsm.gz
I have decompiled the ZSM using zsmtool (a tool I wrote). And it is clear that there's extra stuff at the end.
This last bit definitely doesn't belong.
looptest.yml.gz