How about just using the float value instead of converting to an iterator?
And a template just to cut down on the boilerplate.
import math
const
SampleRate = 44100
Increment = TAU/SampleRate
func `+`*[T](val:T, iter:iterator:T):iterator:T =
return iterator(): T =
while true:
yield val + iter()
func sinOsc*[Tf, Tp, Ta: float or iterator:float](freq:Tf, phase:Tp,
amp:Ta):iterator:float =
var
tick, lastFreq, phaseCorrection:float
template floatIter(x:untyped):untyped =
when x is float: x else: x()
return iterator(): float =
while true:
let
f = floatIter(freq)
p = floatIter(phase)
a = floatIter(amp)
phaseCorrection += (lastFreq - f) * (tick)
lastFreq = f
yield a * sin((tick * f) + phaseCorrection + p)
tick += Increment
let
f20 = sinOsc(20.0, 0.0, 3.0)
fm200 = sinOsc(200.0 + f20, 0.0, 1.0)
for i in 0..100:
echo fm200()
Run