Skip to content

Commit 95af8da

Browse files
committed
fix(vm)!: first modulate delay time, then notetracking
BREAKING CHANGE: the order of these operations was inconsistent across the different VMs. Go VM was the only one to first modulate and then apply note tracking multiplication. But that made most sense. So now all different VM versions work in this same way.
1 parent 78fc630 commit 95af8da

File tree

6 files changed

+73
-19
lines changed

6 files changed

+73
-19
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4545
be computed every draw. ([#176][i176])
4646

4747
### Fixed
48+
- BREAKING CHANGE: always first modulate delay time, then apply notetracking. In
49+
a delay unit, modulation adds to the delay time, while note tracking
50+
multiplies it with a multiplier dependent on the note. The order of these
51+
operations was different in the Go VM vs. x86 VM & WebAssembly VM. In the Go
52+
VM, it first modulated, and then applied the note tracking multiplication. In
53+
the two assembly VMs, it first applied the note tracking and then modulated.
54+
Of these two behaviours, the Go VM behaviour made more sense: if you make a
55+
vibrato of +-50 cents for C4, you probably want a vibrato of +-50 cents for C6
56+
also. Thus, first modulating and then applying the note tracking
57+
multiplication is now the behaviour accross all VMs.
4858
- Loading instrument forgot to close the file (in model.ReadInstrument)
4959
- We try to honor the MIDI event time stamps, so that the timing between MIDI
5060
events (as reported to us by RTMIDI) will be correct.

tests/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ regression_test(test_filter_resmod "VCO_SINE;ENVELOPE;FOP_MULP;SEND")
158158
regression_test(test_delay "ENVELOPE;FOP_MULP;PANNING;VCO_SINE")
159159
regression_test(test_delay_stereo "ENVELOPE;FOP_MULP;PANNING;VCO_SINE")
160160
regression_test(test_delay_notetracking "ENVELOPE;FOP_MULP;PANNING;NOISE")
161+
regression_test(test_delay_notetracking_modulation "ENVELOPE;FOP_MULP;PANNING;NOISE")
161162
regression_test(test_delay_reverb "ENVELOPE;FOP_MULP;PANNING;VCO_SINE")
162163
regression_test(test_delay_feedbackmod "ENVELOPE;FOP_MULP;PANNING;VCO_SINE;SEND")
163164
regression_test(test_delay_pregainmod "ENVELOPE;FOP_MULP;PANNING;VCO_SINE;SEND")
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
bpm: 100
2+
rowsperbeat: 4
3+
score:
4+
tracks:
5+
- numvoices: 1
6+
order: [0]
7+
patterns: [[73, 1, 1, 1, 0, 1, 1, 1, 77, 1, 1, 1, 0]]
8+
rowsperpattern: 16
9+
length: 1
10+
patch:
11+
- name: Instr
12+
numvoices: 1
13+
units:
14+
- type: envelope
15+
id: 1
16+
parameters: {attack: 64, decay: 64, gain: 64, release: 64, stereo: 0, sustain: 64}
17+
- type: noise
18+
id: 10
19+
parameters: {gain: 64, shape: 64, stereo: 0}
20+
- type: filter
21+
id: 12
22+
parameters: {bandpass: 0, frequency: 39, highpass: 0, lowpass: 1, negbandpass: 0, neghighpass: 0, resonance: 128, stereo: 0}
23+
- type: delay
24+
id: 11
25+
parameters: {damp: 0, dry: 71, feedback: 114, notetracking: 1, pregain: 128, stereo: 0}
26+
varargs: [21574]
27+
- type: mulp
28+
id: 3
29+
parameters: {stereo: 0}
30+
- type: pan
31+
id: 5
32+
parameters: {panning: 64, stereo: 0}
33+
- type: out
34+
id: 16
35+
parameters: {gain: 128, stereo: 1}
36+
- id: 13
37+
parameters: {}
38+
- type: oscillator
39+
id: 14
40+
parameters: {color: 128, detune: 64, gain: 5, lfo: 1, phase: 0, shape: 64, stereo: 0, transpose: 76, type: 0}
41+
- type: send
42+
id: 15
43+
parameters: {amount: 96, port: 4, sendpop: 1, stereo: 0, target: 11, voice: 0}

vm/compiler/templates/amd64-386/effects.asm

+6-6
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,12 @@ su_op_delay_mono: ; flow into mono delay
309309
su_op_delay_loop:
310310
{{- if or (.SupportsModulation "delay" "delaytime") (.SupportsParamValue "delay" "notetracking" 1)}} ; delaytime modulation or note syncing require computing the delay time in floats
311311
fild word [{{.BX}}] ; k dr*y p*p*x, where k = delay time
312+
{{- if .SupportsModulation "delay" "delaytime"}}
313+
fld dword [{{.Modulation "delay" "delaytime"}}]
314+
{{- .Float 32767.0 | .Prepare | indent 8}}
315+
fmul dword [{{.Float 32767.0 | .Use}}] ; scale it up, as the modulations would be too small otherwise
316+
faddp st1, st0
317+
{{- end}}
312318
{{- if .SupportsParamValue "delay" "notetracking" 1}}
313319
test ah, 1 ; note syncing is the least significant bit of ah, 0 = ON, 1 = OFF
314320
jne su_op_delay_skipnotesync
@@ -319,12 +325,6 @@ su_op_delay_loop:
319325
fdivp st1, st0 ; use 10787 for delaytime to have neutral transpose
320326
su_op_delay_skipnotesync:
321327
{{- end}}
322-
{{- if .SupportsModulation "delay" "delaytime"}}
323-
fld dword [{{.Modulation "delay" "delaytime"}}]
324-
{{- .Float 32767.0 | .Prepare | indent 8}}
325-
fmul dword [{{.Float 32767.0 | .Use}}] ; scale it up, as the modulations would be too small otherwise
326-
faddp st1, st0
327-
{{- end}}
328328
fistp dword [{{.SP}}-4] ; dr*y p*p*x, dword [{{.SP}}-4] = integer amount of delay (samples)
329329
mov edi, esi ; edi = esi = current time
330330
sub di, word [{{.SP}}-4] ; we perform the math in 16-bit to wrap around

vm/compiler/templates/wasm/effects.wat

+13-13
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,23 @@
295295
(i32.sub ;; globalTick-delaytimes[delayIndex]
296296
(global.get $globaltick)
297297
{{- if or (.SupportsModulation "delay" "delaytime") (.SupportsParamValue "delay" "notetracking" 1)}} ;; delaytime modulation or note syncing require computing the delay time in floats
298+
{{- if .SupportsModulation "delay" "delaytime"}}
299+
(local.set $delayTime (f32.add
300+
(f32.convert_i32_u (i32.load16_u
301+
offset={{index .Labels "su_delay_times"}}
302+
(local.get $delayIndex)
303+
))
304+
(f32.mul
305+
(f32.load offset={{.InputNumber "delay" "delaytime" | mul 4 | add 32}} (global.get $WRK))
306+
(f32.const 32767)
307+
)
308+
))
309+
{{- else}}
298310
(local.set $delayTime (f32.convert_i32_u (i32.load16_u
299311
offset={{index .Labels "su_delay_times"}}
300312
(local.get $delayIndex)
301313
)))
314+
{{- end}}
302315
{{- if .SupportsParamValue "delay" "notetracking" 1}}
303316
(if (i32.eqz (i32.and (local.get $delayCount) (i32.const 1)))(then
304317
(local.set $delayTime (f32.div
@@ -312,20 +325,7 @@
312325
))
313326
))
314327
{{- end}}
315-
{{- if .SupportsModulation "delay" "delaytime"}}
316-
(i32.trunc_f32_s (f32.add
317-
(f32.add
318-
(local.get $delayTime)
319-
(f32.mul
320-
(f32.load offset={{.InputNumber "delay" "delaytime" | mul 4 | add 32}} (global.get $WRK))
321-
(f32.const 32767)
322-
)
323-
)
324-
(f32.const 0.5)
325-
))
326-
{{- else}}
327328
(i32.trunc_f32_s (f32.add (local.get $delayTime) (f32.const 0.5)))
328-
{{- end}}
329329
{{- else}}
330330
(i32.load16_u
331331
offset={{index .Labels "su_delay_times"}}

0 commit comments

Comments
 (0)