mirror of
https://github.com/vsariola/sointu.git
synced 2026-02-28 19:13:20 -05:00
fix(vm): avoid NaNs in trisaw oscillator
This commit is contained in:
parent
92859a5e58
commit
4d29a191c8
@ -269,7 +269,10 @@ su_oscillat_pulse_up:
|
||||
{{- if .HasCall "su_oscillat_trisaw"}}
|
||||
{{.Func "su_oscillat_trisaw"}}
|
||||
fucomi st1 ; // c p
|
||||
jnc short su_oscillat_trisaw_up
|
||||
; we do jnbe instead of jnc to avoid NaN. phase cannot be < 0 or >= 1, so the important cases are
|
||||
; c = 0 => the branch is never taken, because c > p can never happen, and thus results in .../(1-c)
|
||||
; c = 1 => the branch is always taken, because p < c and thus always gives .../c
|
||||
jnbe short su_oscillat_trisaw_up
|
||||
fld1 ; // 1 c p
|
||||
fsubr st2, st0 ; // 1 c 1-p
|
||||
fsubrp st1, st0 ; // 1-c 1-p
|
||||
|
||||
@ -481,10 +481,10 @@ func (s *GoSynth) Render(buffer sointu.AudioBuffer, maxtime int) (samples int, r
|
||||
}
|
||||
omega += float64(unit.ports[6]) // add frequency modulation
|
||||
var amplitude float32
|
||||
*statevar += float32(omega)
|
||||
phase := float64(*statevar) + omega
|
||||
if flags&0x80 == 0x80 { // if this is a sample oscillator
|
||||
phase := *statevar
|
||||
phase += params[2]
|
||||
*statevar = float32(phase)
|
||||
phase += float64(params[2])
|
||||
sampleno := operandsAtTransform[3] // reuse color as the sample number
|
||||
sampleoffset := s.bytecode.SampleOffsets[sampleno]
|
||||
sampleindex := int(phase*84.28074964676522 + 0.5)
|
||||
@ -497,22 +497,25 @@ func (s *GoSynth) Render(buffer sointu.AudioBuffer, maxtime int) (samples int, r
|
||||
sampleindex += int(sampleoffset.Start)
|
||||
amplitude = float32(int16(binary.LittleEndian.Uint16(su_sample_table[sampleindex*2:]))) / 32767.0
|
||||
} else {
|
||||
*statevar -= float32(int(*statevar+1) - 1)
|
||||
phase := *statevar
|
||||
phase += params[2]
|
||||
phase -= float32(int(phase+1) - 1)
|
||||
color := params[3]
|
||||
// at this point, the native synth actually uses 80-bit precision, so emulate that as closely as possible by using 64-bit math here
|
||||
phase += 1
|
||||
phase -= float64(int(phase))
|
||||
*statevar = float32(phase)
|
||||
phase += float64(params[2])
|
||||
phase += 1
|
||||
phase -= float64(int(phase)) // this should guaranteee that phase is [0,1), so that the Trisaw should not nan even if color = 1
|
||||
color := float64(params[3])
|
||||
switch {
|
||||
case flags&0x40 == 0x40: // Sine
|
||||
if phase < color {
|
||||
amplitude = float32(math.Sin(2 * math.Pi * float64(phase/color)))
|
||||
amplitude = float32(math.Sin(2 * math.Pi * phase / color))
|
||||
}
|
||||
case flags&0x20 == 0x20: // Trisaw
|
||||
if phase >= color {
|
||||
if phase >= color { // since phase cannot be 1, if color = 1, then this condition never fires
|
||||
phase = 1 - phase
|
||||
color = 1 - color
|
||||
}
|
||||
amplitude = phase/color*2 - 1
|
||||
amplitude = float32(phase/color*2 - 1)
|
||||
case flags&0x10 == 0x10: // Pulse
|
||||
if phase >= color {
|
||||
amplitude = -1
|
||||
|
||||
Reference in New Issue
Block a user