{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module Synthesizer.Basic.WaveSmoothed (
T,
fromFunction,
fromWave,
fromControlledWave,
raise,
amplify,
distort,
apply,
sine,
cosine,
saw,
square,
triangle,
Wave.Harmonic,
Wave.harmonic,
composedHarmonics,
) where
import qualified Synthesizer.Basic.Wave as Wave
import qualified Synthesizer.Basic.Phase as Phase
import qualified Algebra.Transcendental as Trans
import qualified Algebra.Module as Module
import qualified Algebra.Field as Field
import qualified Algebra.RealRing as RealRing
import qualified Algebra.Ring as Ring
import qualified Algebra.Additive as Additive
import qualified MathObj.Polynomial as Poly
import qualified Number.Complex as Complex
import NumericPrelude.Numeric
import NumericPrelude.Base
newtype T t y = Cons {decons :: t -> Phase.T t -> y}
{-# INLINE fromFunction #-}
fromFunction :: (t -> t -> y) -> (T t y)
fromFunction wave =
Cons (\f p -> wave f (Phase.toRepresentative p))
{-# INLINE fromWave #-}
fromWave ::
(Field.C t, RealRing.C t, Additive.C y) =>
Wave.T t y -> (T t y)
fromWave wave =
fromControlledWaveAux (\f -> if abs f >= 1/2 then zero else wave)
{-# INLINE fromControlledWave #-}
fromControlledWave ::
(Field.C t, RealRing.C t, Additive.C y) =>
(t -> Wave.T t y) -> (T t y)
fromControlledWave wave =
fromControlledWaveAux (\f0 ->
let f = abs f0
in if f >= 1/2
then zero
else wave f)
{-# INLINE fromControlledWaveAux #-}
fromControlledWaveAux :: (t -> Wave.T t y) -> (T t y)
fromControlledWaveAux wave =
Cons (\f p -> Wave.apply (wave f) p)
{-# INLINE raise #-}
raise :: (Additive.C y) => y -> T t y -> T t y
raise y = distort (y+)
{-# INLINE amplify #-}
amplify :: (Ring.C y) => y -> T t y -> T t y
amplify k = distort (k*)
{-# INLINE distort #-}
distort :: (y -> z) -> T t y -> T t z
distort g (Cons w) = Cons (\f p -> g (w f p))
{-# INLINE apply #-}
apply :: T t y -> (t -> Phase.T t -> y)
apply = decons
instance Additive.C y => Additive.C (T t y) where
{-# INLINE zero #-}
{-# INLINE (+) #-}
{-# INLINE (-) #-}
{-# INLINE negate #-}
zero = Cons (const zero)
(+) (Cons w) (Cons v) = Cons (\f p -> w f p + v f p)
(-) (Cons w) (Cons v) = Cons (\f p -> w f p - v f p)
negate = distort negate
instance Module.C a y => Module.C a (T t y) where
{-# INLINE (*>) #-}
s *> w = distort (s*>) w
{-# INLINE sine #-}
sine :: (Trans.C a, RealRing.C a) => T a a
sine = fromWave Wave.sine
{-# INLINE cosine #-}
cosine :: (Trans.C a, RealRing.C a) => T a a
cosine = fromWave Wave.cosine
{-# INLINE saw #-}
saw :: (RealRing.C a, Field.C a) => T a a
saw =
fromControlledWave (\f -> Wave.triangleAsymmetric (2*f-1))
{-# INLINE square #-}
square :: (RealRing.C a, Field.C a) => T a a
square =
fromControlledWave (\f -> Wave.trapezoid (1-2*f))
{-# INLINE triangle #-}
triangle :: (RealRing.C a, Field.C a) => T a a
triangle = fromWave Wave.triangle
{-# INLINE composedHarmonics #-}
composedHarmonics :: (Trans.C a, RealRing.C a) => [Wave.Harmonic a] -> T a a
composedHarmonics hs =
let c = map (\h -> Complex.fromPolar (Wave.harmonicAmplitude h)
(2*pi * Phase.toRepresentative (Wave.harmonicPhase h))) hs
trunc f =
map snd . takeWhile ((<1/2) . fst) . zip (iterate (abs f +) zero)
in fromControlledWaveAux $ \f ->
Wave.distort
(Complex.imag . Poly.evaluate (Poly.fromCoeffs (trunc f c)))
Wave.helix