module Csound.Air.Wave (
	 
    osc, oscBy, saw, isaw, pulse, sqr, pw, tri, ramp, blosc,
    
    osc', oscBy', saw', isaw', pulse', sqr', pw', tri', ramp', blosc',
    
    rndOsc, rndOscBy, rndSaw, rndIsaw, rndPulse, rndSqr, rndPw, rndTri, rndRamp, rndBlosc,    
    
    unipolar, bipolar, uosc, uoscBy, usaw, uisaw, upulse, usqr, upw, utri, uramp, ublosc,
    
    uosc', uoscBy', usaw', uisaw', upulse', usqr', upw', utri', uramp', ublosc',
    
    urndOsc, urndOscBy, urndSaw, urndIsaw, urndPulse, urndSqr, urndPw, urndTri, urndRamp, urndBlosc,        
    
    rndh, urndh, rndi, urndi, white, pink,
    
    fosc,
    
    Lfo, lfo,
    
    detune,
    
    multiHz, multiCent, multiRnd, multiGauss, multiRndSE, multiGaussSE,
    
    urspline, birspline
) where
import Csound.Typed
import Csound.Typed.Opcode hiding (lfo)
import Csound.Tab(sine, sines4)
import Csound.SigSpace
osc :: Sig -> Sig
osc cps = oscil3 1 cps sine 
osc' :: D -> Sig -> Sig
osc' phase cps = oscil3 1 cps sine `withD` phase
oscBy :: Tab -> Sig -> Sig
oscBy tb cps = oscil3 1 cps tb
oscBy' :: Tab -> D -> Sig -> Sig
oscBy' tb phase cps = oscil3 1 cps tb `withD` phase
unipolar :: Sig -> Sig
unipolar a = 0.5 + 0.5 * a
bipolar :: Sig -> Sig
bipolar a = 2 * a  1
uosc :: Sig -> Sig
uosc = unipolar . osc
uoscBy :: Tab -> Sig -> Sig
uoscBy tb = unipolar . oscBy tb
usaw :: Sig -> Sig
usaw = unipolar . saw
uisaw :: Sig -> Sig
uisaw = unipolar . isaw
usqr :: Sig -> Sig
usqr = unipolar . sqr
utri :: Sig -> Sig
utri = unipolar . tri
upulse :: Sig -> Sig
upulse = unipolar . pulse
ublosc :: Tab -> Sig -> Sig
ublosc tb = unipolar . blosc tb
urspline :: Sig -> Sig -> SE Sig
urspline cpsMin cpsMax = rspline 0 1 cpsMin cpsMax
birspline :: Sig -> Sig -> SE Sig
birspline cpsMin cpsMax = rspline (1) 1 cpsMin cpsMax
fosc :: Sig -> Sig -> Sig -> Sig -> Sig
fosc car mod ndx cps = foscili 1 cps car mod ndx sine
pw :: Sig -> Sig -> Sig
pw duty cps = vco2 1 cps `withD` 2 `withSig` duty
pw' :: Sig -> D -> Sig -> Sig
pw' duty phase cps = vco2 1 cps `withD` 2 `withSig` duty `withD` phase
ramp :: Sig -> Sig -> Sig
ramp duty cps = vco2 1 cps `withD` 4 `withSig` (uon 0.01 0.99 $ duty)
ramp' :: Sig -> D -> Sig -> Sig
ramp' duty phase cps = vco2 1 cps `withD` 4 `withSig` (uon 0.01 0.99 $ duty) `withD` phase
upw :: Sig -> Sig -> Sig
upw duty cps = unipolar $ pw duty cps
uramp :: Sig -> Sig -> Sig
uramp duty cps = unipolar $ ramp duty cps
unipolar' :: (D -> Sig -> Sig) -> (D -> Sig -> Sig)
unipolar' f phs cps = unipolar $ f phs cps 
uosc' = unipolar' osc'
uoscBy' a = unipolar' (oscBy' a) 
usaw' = unipolar' saw'
uisaw' = unipolar' isaw' 
upulse' = unipolar' pulse' 
usqr' = unipolar' sqr'
upw' a = unipolar' (pw' a)
utri' = unipolar' tri'
uramp' a = unipolar' (ramp' a)
ublosc' a = unipolar' (blosc' a)
rndPhs :: (D -> Sig -> Sig) -> (Sig -> SE Sig)
rndPhs f cps = fmap (\x -> f x cps) $ rnd 1
rndOsc = rndPhs osc'
rndOscBy a = rndPhs (oscBy' a)
rndSaw = rndPhs saw' 
rndIsaw = rndPhs isaw'
rndPulse = rndPhs pulse'
rndSqr = rndPhs sqr'
rndPw a = rndPhs (pw' a)
rndTri = rndPhs tri'
rndRamp a = rndPhs (ramp' a)
rndBlosc a = rndPhs (blosc' a)
urndOsc = rndPhs uosc'
urndOscBy a = rndPhs (uoscBy' a)
urndSaw = rndPhs usaw' 
urndIsaw = rndPhs uisaw'
urndPulse = rndPhs upulse'
urndSqr = rndPhs usqr'
urndPw a = rndPhs (upw' a)
urndTri = rndPhs utri'
urndRamp a = rndPhs (uramp' a)
urndBlosc a = rndPhs (ublosc' a)
rndh :: Sig -> SE Sig
rndh = randh 1
rndi :: Sig -> SE Sig
rndi = randi 1
urndh :: Sig -> SE Sig
urndh = fmap unipolar . rndh
urndi :: Sig -> SE Sig
urndi = fmap unipolar . rndi
white :: SE Sig 
white = noise 1 0
pink :: SE Sig
pink = pinkish 1
type Lfo = Sig
lfo :: (Sig -> Sig) -> Sig -> Sig -> Sig
lfo shape depth rate = depth * shape rate
detune :: Sig -> (Sig -> a) -> (Sig -> a)
detune k f cps = f (k * cps) 
linRange n amount = fmap (\x -> amount * sig (2 * double x  1)) [0, (1 / fromIntegral n) .. 1] 
multiHz :: Fractional a => Int -> Sig -> (Sig -> a) -> (Sig -> a) 
multiHz n amount f cps = mean $ fmap (f . (cps + )) $ linRange n amount
multiCent :: Fractional a => Int -> Sig -> (Sig -> a) -> (Sig -> a) 
multiCent n amount f cps = mean $ fmap (f . (cps * ) . cent) $ linRange n amount
    
multiRnd :: Fractional a => Int -> Sig -> (Sig -> a) -> (Sig -> SE a)
multiRnd = genMultiRnd (rnd 1)
multiGauss :: Fractional a => Int -> Sig -> (Sig -> a) -> (Sig -> SE a)
multiGauss = genMultiRnd (fmap ((+ 0.5) . ir) $ gauss 0.5)
genMultiRnd :: Fractional a => (SE D) -> Int -> Sig -> (Sig -> a) -> (Sig -> SE a)
genMultiRnd gen n amount f cps = fmap mean $ mapM (const go) $ replicate n ()
    where go = fmap (\dx -> f $ cps + amount * (sig $ 2 * dx  1)) gen
multiRndSE :: Fractional a => Int -> Sig -> (Sig -> SE a) -> (Sig -> SE a)
multiRndSE = genMultiRndSE (rnd 1)
multiGaussSE :: Fractional a => Int -> Sig -> (Sig -> SE a) -> (Sig -> SE a)
multiGaussSE = genMultiRndSE (fmap ((+ 0.5) . ir) $ gauss 0.5)
genMultiRndSE :: Fractional a => (SE D) -> Int -> Sig -> (Sig -> SE a) -> (Sig -> SE a)
genMultiRndSE gen n amount f cps = fmap mean $ mapM (const go) $ replicate n ()
    where go = (\dx -> f $ cps * cent (amount * (sig $ 2 * dx  1))) =<< gen
mean :: Fractional a => [a] -> a
mean xs = sum xs / (fromIntegral $ length xs)