The code below works. But I'm not happy with the use of iterFloat and the solution in sinOsc. I'd like to use a float when given and I'd like the selection process before the return iterator(). I tried with a template but that led to nothing, lack of understanding on my side. Are templates the way to go here? If so, how?
And a small question on return iterator(), return iterator seems to work to. Should it? What's proper?
import math
const
SampleRate = 44100
Increment = TAU/SampleRate
func iterFloat(val:float):iterator:float =
return iterator(): float =
while true:
yield val
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
when freq is float:
let freq = iterFloat(freq)
when phase is float:
let phase = iterFloat(phase)
when amp is float:
let amp = iterFloat(amp)
return iterator(): float =
while true:
let
f = freq()
p = phase()
a = 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()
TIA
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()