tildearrow / furnace

a multi-system chiptune tracker compatible with DefleMask modules
GNU General Public License v2.0
2.68k stars 210 forks source link

ZSM export seems to write out an extra tick before the loop #1058

Closed mooinglemur closed 1 year ago

mooinglemur commented 1 year ago

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.

  - ym_write:  # YM write block: 2 (0x02) events
    - addr: 0x08  # Key Control
      data: 0x00 # Key off, channel 0
    - addr: 0x08  # Key Control
      data: 0x78 # Key on, channel 0
  - delay: 0x01  # 1 ticks (0.02s), total 97 (0m01.62s) 

looptest.yml.gz

mooinglemur commented 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. :)

tildearrow commented 1 year ago

I have a feeling that this is intentional. Does this happen when loop is disabled?

mooinglemur commented 1 year ago

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
mooinglemur commented 1 year ago

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
mooinglemur commented 1 year ago

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.

tildearrow commented 1 year ago

Fixed by #1191. Hoping it doesn't break things after loop (especially FM).