mirror of
https://github.com/vsariola/sointu.git
synced 2026-04-12 17:14:43 -04:00
fix(vm): avoid NaNs in trisaw oscillator
This commit is contained in:
parent
92859a5e58
commit
4d29a191c8
@ -40,7 +40,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- VSTi queries the host sample rate more robustly. Cubase previously reported
|
- VSTi queries the host sample rate more robustly. Cubase previously reported
|
||||||
the sample rate as 0 Hz, leading to persistent error message about the sample
|
the sample rate as 0 Hz, leading to persistent error message about the sample
|
||||||
rate not being 44100 Hz. ([#222][i222])
|
rate not being 44100 Hz. ([#222][i222])
|
||||||
- Occasional NaNs in the Trisaw oscillator when the color was 0 in the Go VM.
|
- Occasional NaNs in the Trisaw oscillator when color was = 0 or color = 128
|
||||||
- The tracker thought that "sync" unit pops the value from stack, even if the VM
|
- The tracker thought that "sync" unit pops the value from stack, even if the VM
|
||||||
did not, resulting it claiming errors in patches that worked once compiled.
|
did not, resulting it claiming errors in patches that worked once compiled.
|
||||||
|
|
||||||
|
|||||||
@ -269,7 +269,10 @@ su_oscillat_pulse_up:
|
|||||||
{{- if .HasCall "su_oscillat_trisaw"}}
|
{{- if .HasCall "su_oscillat_trisaw"}}
|
||||||
{{.Func "su_oscillat_trisaw"}}
|
{{.Func "su_oscillat_trisaw"}}
|
||||||
fucomi st1 ; // c p
|
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
|
fld1 ; // 1 c p
|
||||||
fsubr st2, st0 ; // 1 c 1-p
|
fsubr st2, st0 ; // 1 c 1-p
|
||||||
fsubrp st1, 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
|
omega += float64(unit.ports[6]) // add frequency modulation
|
||||||
var amplitude float32
|
var amplitude float32
|
||||||
*statevar += float32(omega)
|
phase := float64(*statevar) + omega
|
||||||
if flags&0x80 == 0x80 { // if this is a sample oscillator
|
if flags&0x80 == 0x80 { // if this is a sample oscillator
|
||||||
phase := *statevar
|
*statevar = float32(phase)
|
||||||
phase += params[2]
|
phase += float64(params[2])
|
||||||
sampleno := operandsAtTransform[3] // reuse color as the sample number
|
sampleno := operandsAtTransform[3] // reuse color as the sample number
|
||||||
sampleoffset := s.bytecode.SampleOffsets[sampleno]
|
sampleoffset := s.bytecode.SampleOffsets[sampleno]
|
||||||
sampleindex := int(phase*84.28074964676522 + 0.5)
|
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)
|
sampleindex += int(sampleoffset.Start)
|
||||||
amplitude = float32(int16(binary.LittleEndian.Uint16(su_sample_table[sampleindex*2:]))) / 32767.0
|
amplitude = float32(int16(binary.LittleEndian.Uint16(su_sample_table[sampleindex*2:]))) / 32767.0
|
||||||
} else {
|
} else {
|
||||||
*statevar -= float32(int(*statevar+1) - 1)
|
// 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 := *statevar
|
phase += 1
|
||||||
phase += params[2]
|
phase -= float64(int(phase))
|
||||||
phase -= float32(int(phase+1) - 1)
|
*statevar = float32(phase)
|
||||||
color := params[3]
|
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 {
|
switch {
|
||||||
case flags&0x40 == 0x40: // Sine
|
case flags&0x40 == 0x40: // Sine
|
||||||
if phase < color {
|
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
|
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
|
phase = 1 - phase
|
||||||
color = 1 - color
|
color = 1 - color
|
||||||
}
|
}
|
||||||
amplitude = phase/color*2 - 1
|
amplitude = float32(phase/color*2 - 1)
|
||||||
case flags&0x10 == 0x10: // Pulse
|
case flags&0x10 == 0x10: // Pulse
|
||||||
if phase >= color {
|
if phase >= color {
|
||||||
amplitude = -1
|
amplitude = -1
|
||||||
|
|||||||
Reference in New Issue
Block a user