{-# LANGUAGE NoImplicitPrelude #-}
{- |
Copyright   :  (c) Henning Thielemann 2010
License     :  GPL

Maintainer  :  synthesizer@henning-thielemann.de
Stability   :  provisional
Portability :  requires multi-parameter type classes

Basics for building tone generators.
They generate signals of phases
and these signals can be converted to arbitrary waveforms
by mapping them via @Wave@ objects.
This is also the fundament for dimensional oscillators.
-}
module Synthesizer.Causal.Oscillator.Core where

import qualified Synthesizer.Basic.Phase as Phase

import qualified Synthesizer.Causal.Process as Causal
import qualified Synthesizer.State.Signal as Sig

import Control.Arrow ((^<<), (&&&), second, returnA, )

import qualified Algebra.RealRing             as RealRing

import NumericPrelude.Numeric
import NumericPrelude.Base



{-# INLINE static #-}
static :: RealRing.C a =>
   Phase.T a -> a -> Sig.T (Phase.T a)
static :: forall a. C a => T a -> a -> T (T a)
static T a
phase a
freq =
   (T a -> T a) -> T a -> T (T a)
forall a. (a -> a) -> a -> T a
Sig.iterate (a -> T a -> T a
forall a. C a => a -> T a -> T a
Phase.increment a
freq) T a
phase


{-# INLINE phaseMod #-}
{- | oscillator with modulated phase -}
phaseMod :: (RealRing.C a) =>
   a -> Causal.T a (Phase.T a)
phaseMod :: forall a. C a => a -> T a (T a)
phaseMod a
freq =
   (a -> T a -> T a) -> (a, T a) -> T a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry a -> T a -> T a
forall a. C a => a -> T a -> T a
Phase.increment ((a, T a) -> T a) -> T a (a, T a) -> T a (T a)
forall (a :: * -> * -> *) c d b.
Arrow a =>
(c -> d) -> a b c -> a b d
^<<
      T (T a) -> T a (a, T a)
forall (sig :: * -> *) a b. Read sig a => sig a -> T b (b, a)
Causal.feedSnd (T a -> a -> T (T a)
forall a. C a => T a -> a -> T (T a)
static T a
forall a. C a => a
zero a
freq)

{-# INLINE shapeMod #-}
{- | oscillator with modulated shape -}
shapeMod :: (RealRing.C a) =>
   Phase.T a -> a -> Causal.T c (c, Phase.T a)
shapeMod :: forall a c. C a => T a -> a -> T c (c, T a)
shapeMod T a
phase a
freq =
   T (T a) -> T c (c, T a)
forall (sig :: * -> *) a b. Read sig a => sig a -> T b (b, a)
Causal.feedSnd (T a -> a -> T (T a)
forall a. C a => T a -> a -> T (T a)
static T a
phase a
freq)

{-# INLINE freqMod #-}
{- |
Convert a list of phase steps into a list of momentum phases.
phase is a number in the interval [0,1).
freq contains the phase steps.
The last element is omitted.
-}
freqMod :: RealRing.C a =>
   Phase.T a -> Causal.T a (Phase.T a)
freqMod :: forall a. C a => T a -> T a (T a)
freqMod =
   (T a -> a -> T a) -> T a -> T a (T a)
forall acc x. (acc -> x -> acc) -> acc -> T x acc
Causal.scanL ((a -> T a -> T a) -> T a -> a -> T a
forall a b c. (a -> b -> c) -> b -> a -> c
flip a -> T a -> T a
forall a. C a => a -> T a -> T a
Phase.increment)

{- |
Like 'freqMod' but the first element is omitted.
-}
{-# INLINE freqModSync #-}
freqModSync :: RealRing.C a =>
   Phase.T a -> Causal.T a (Phase.T a)
freqModSync :: forall a. C a => T a -> T a (T a)
freqModSync =
   (a -> T a -> Maybe (T a, T a)) -> T a -> T a (T a)
forall x acc y. (x -> acc -> Maybe (y, acc)) -> acc -> T x y
Causal.crochetL
      (\a
f T a
p0 -> let p1 :: T a
p1 = a -> T a -> T a
forall a. C a => a -> T a -> T a
Phase.increment a
f T a
p0 in (T a, T a) -> Maybe (T a, T a)
forall a. a -> Maybe a
Just (T a
p1,T a
p1))


{-# INLINE freqModAntiAlias #-}
{- | oscillator with modulated frequency -}
freqModAntiAlias :: (RealRing.C a) =>
   Phase.T a -> Causal.T a (a, Phase.T a)
freqModAntiAlias :: forall a. C a => T a -> T a (a, T a)
freqModAntiAlias T a
phase =
   T a a
forall (a :: * -> * -> *) b. Arrow a => a b b
returnA T a a -> T a (T a) -> T a (a, T a)
forall b c c'. T b c -> T b c' -> T b (c, c')
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& T a -> T a (T a)
forall a. C a => T a -> T a (T a)
freqMod T a
phase

{-# INLINE phaseFreqMod #-}
{- | oscillator with both phase and frequency modulation -}
phaseFreqMod :: (RealRing.C a) =>
   Causal.T (a,a) (Phase.T a)
phaseFreqMod :: forall a. C a => T (a, a) (T a)
phaseFreqMod =
   (a -> T a -> T a) -> (a, T a) -> T a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry a -> T a -> T a
forall a. C a => a -> T a -> T a
Phase.increment ((a, T a) -> T a) -> T (a, a) (a, T a) -> T (a, a) (T a)
forall (a :: * -> * -> *) c d b.
Arrow a =>
(c -> d) -> a b c -> a b d
^<<
   T a (T a) -> T (a, a) (a, T a)
forall b c d. T b c -> T (d, b) (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second (T a -> T a (T a)
forall a. C a => T a -> T a (T a)
freqMod T a
forall a. C a => a
zero)

{-# INLINE shapeFreqMod #-}
{- | oscillator with both shape and frequency modulation -}
shapeFreqMod :: (RealRing.C a) =>
   Phase.T a -> Causal.T (c,a) (c, Phase.T a)
shapeFreqMod :: forall a c. C a => T a -> T (c, a) (c, T a)
shapeFreqMod T a
phase =
   T a (T a) -> T (c, a) (c, T a)
forall b c d. T b c -> T (d, b) (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second (T a -> T a (T a)
forall a. C a => T a -> T a (T a)
freqMod T a
phase)