fix(asm/wasm): oscillator phase was causing rounding errors once large enough

gopher had fixed this, but we foolishly removed it. reintroducing fix, although this could be optional only for those who really care. ultimate size optimizers could still want to get rid of it.
This commit is contained in:
Veikko Sariola 2020-12-30 21:19:27 +02:00
parent 7974f0ff82
commit c02c5c3c3d
47 changed files with 43 additions and 25 deletions

View File

@ -172,20 +172,31 @@ su_op_oscillat_normalize_note:
fmul dword [{{.Float 0.000092696138 | .Use}}] ; // st0 is now frequency
su_op_oscillat_normalized:
fadd dword [{{.WRK}}]
fst dword [{{.WRK}}]
fadd dword [{{.Input "oscillator" "phase"}}]
{{- if .SupportsParamValue "oscillator" "type" .Sample}}
test al, byte 0x80
jz short su_op_oscillat_not_sample
fst dword [{{.WRK}}] ; for samples, we store the phase without mod(p,1)
{{- if or (.SupportsParamValueOtherThan "oscillator" "phase" 0) (.SupportsModulation "oscillator" "phase")}}
fadd dword [{{.Input "oscillator" "phase"}}]
{{- end}}
{{.Call "su_oscillat_sample"}}
jmp su_op_oscillat_shaping ; skip the rest to avoid color phase normalization and colorloading
su_op_oscillat_not_sample:
{{- end}}
fld1
fadd st1, st0
fld1 ; we need to take mod(p,1) so the frequency does not drift as the float
fadd st1, st0 ; make no mistake: without this, there is audible drifts in oscillator pitch
fxch ; as the actual period changes once the phase becomes too big
fprem ; we actually computed mod(p+1,1) instead of mod(p,1) as the fprem takes mod
fstp st1 ; towards zero
fst dword [{{.WRK}}] ; store back the updated phase
{{- if or (.SupportsParamValueOtherThan "oscillator" "phase" 0) (.SupportsModulation "oscillator" "phase")}}
fadd dword [{{.Input "oscillator" "phase"}}]
fld1 ; this is a bit stupid, but we need to take mod(x,1) again after phase modulations
fadd st1, st0 ; as the actual oscillator functions expect x in [0,1]
fxch
fprem
fstp st1
{{- end}}
fld dword [{{.Input "oscillator" "color"}}] ; // c p
; every oscillator test included if needed
{{- if .SupportsParamValue "oscillator" "type" .Sine}}

View File

@ -121,27 +121,34 @@
{{- end}}
(f32.store ;; update phase
(global.get $WRK)
;; Transpose calculation starts
(f32.div
(call $inputSigned (i32.const {{.InputNumber "oscillator" "transpose"}}))
(f32.const 0.015625)
) ;; scale back to 0 - 128
(f32.add (local.get $detune)) ;; add detune. detune is -1 to 1 so can detune a full note up or down at max
(f32.add (select
(f32.const 0)
(f32.convert_i32_u (i32.load (global.get $voice)))
(i32.and (local.get $flags) (i32.const 0x8))
)) ;; if lfo is not enabled, add the note number to it
(f32.mul (f32.const 0.0833333)) ;; /12, in full octaves
(call $pow2)
(f32.mul (select
(f32.const 0.000038) ;; pretty random scaling constant to get LFOs into reasonable range. Historical reasons, goes all the way back to 4klang
(f32.const 0.000092696138) ;; scaling constant to get middle-C to where it should be
(i32.and (local.get $flags) (i32.const 0x8))
))
(f32.add (f32.load (global.get $WRK))) ;; add the current phase of the oscillator
(local.tee $phase
(f32.sub
(local.tee $phase
;; Transpose calculation starts
(f32.div
(call $inputSigned (i32.const {{.InputNumber "oscillator" "transpose"}}))
(f32.const 0.015625)
) ;; scale back to 0 - 128
(f32.add (local.get $detune)) ;; add detune. detune is -1 to 1 so can detune a full note up or down at max
(f32.add (select
(f32.const 0)
(f32.convert_i32_u (i32.load (global.get $voice)))
(i32.and (local.get $flags) (i32.const 0x8))
)) ;; if lfo is not enabled, add the note number to it
(f32.mul (f32.const 0.0833333)) ;; /12, in full octaves
(call $pow2)
(f32.mul (select
(f32.const 0.000038) ;; pretty random scaling constant to get LFOs into reasonable range. Historical reasons, goes all the way back to 4klang
(f32.const 0.000092696138) ;; scaling constant to get middle-C to where it should be
(i32.and (local.get $flags) (i32.const 0x8))
))
(f32.add (f32.load (global.get $WRK))) ;; add the current phase of the oscillator
)
(f32.floor (local.get $phase))
)
)
)
(f32.add (f32.load (global.get $WRK)) (call $input (i32.const {{.InputNumber "oscillator" "phase"}})))
(f32.add (local.get $phase) (call $input (i32.const {{.InputNumber "oscillator" "phase"}})))
(local.set $phase (f32.sub (local.tee $phase) (f32.floor (local.get $phase)))) ;; phase = phase mod 1.0
(local.set $color (call $input (i32.const {{.InputNumber "oscillator" "color"}})))
{{- if .SupportsParamValue "oscillator" "type" .Sine}}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -85,7 +85,7 @@ if (process.argv.length <= 3) {
}
errorCount++
}
if (errorCount > 100) {
if (errorCount > 200) {
console.error("got different buffer than expected. First error at: "+(firstErrorPos/2|0)+(firstErrorPos%1," right"," left"));
return 1;
}