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

Reply via email to