{- |
Turn frequency information into signals of phases.
This is mainly the fundament for implementation of oscillators
but you may also use it for generating coherent waves of different form.
-}
module Synthesizer.Dimensional.Causal.Oscillator.Core where

import qualified Synthesizer.Causal.Oscillator.Core as Osci
import qualified Synthesizer.Dimensional.Causal.Process as CausalD
import Synthesizer.Causal.Filter.NonRecursive (amplify, )
import Control.Arrow ((<<<), second, )

import qualified Synthesizer.Dimensional.Sample as Sample
import qualified Synthesizer.Dimensional.Amplitude as Amp
import qualified Synthesizer.Dimensional.Rate as Rate
import qualified Synthesizer.Basic.Phase  as Phase
import Synthesizer.Dimensional.Wave (SamplePhase, )

import qualified Synthesizer.State.Signal as Sig

import qualified Synthesizer.Dimensional.Signal.Private as SigA
import qualified Synthesizer.Dimensional.Process as Proc
import Synthesizer.Dimensional.Process (toFrequencyScalar, )

import qualified Number.DimensionTerm        as DN
import qualified Algebra.DimensionTerm       as Dim
-- import Number.DimensionTerm ((&*&))

import qualified Algebra.RealField          as RealField
-- import qualified Algebra.Field              as Field
-- import qualified Algebra.Ring               as Ring

-- import NumericPrelude.Numeric
-- import NumericPrelude.Base as P


type Frequency u t = Amp.Numeric (DN.T (Dim.Recip u) t)
type SampleFrequency u t = Sample.T (Frequency u t) t


{-# INLINE static #-}
static ::
   (RealField.C t, Dim.C u) =>
      Phase.T t    {- ^ start phase -}
   -> DN.T (Dim.Recip u) t
                   {- ^ frequency -}
   -> Proc.T s u t
         (SigA.T (Rate.Phantom s) Amp.Abstract (Sig.T (Phase.T t)))
--         (Signal s Amp.Abstract (Phase.T t))
static phase freq =
   flip fmap (toFrequencyScalar freq) $ \f ->
   SigA.Cons Rate.Phantom Amp.Abstract $
   Osci.static phase f

{-# INLINE phaseMod #-}
phaseMod :: (RealField.C t, Dim.C u) =>
      DN.T (Dim.Recip u) t    {- ^ frequency -}
   -> Proc.T s u t
         (CausalD.T s (Sample.Flat t) (SamplePhase t))
phaseMod freq =
   flip fmap (toFrequencyScalar freq) $ \f ->
   CausalD.consFlip $ \Amp.Flat ->
      (Amp.Abstract, Osci.phaseMod f)

{-# INLINE freqMod #-}
freqMod :: (RealField.C t, Dim.C u) =>
      Phase.T t    {- ^ phase -}
   -> Proc.T s u t
         (CausalD.T s (SampleFrequency u t) (SamplePhase t))
freqMod phase =
   flip fmap (Proc.withParam toFrequencyScalar) $ \toFreq ->
   CausalD.consFlip $ \(Amp.Numeric freqAmp) ->
      (Amp.Abstract,
       Osci.freqMod phase <<< amplify (toFreq freqAmp))

{-# INLINE phaseFreqMod #-}
phaseFreqMod :: (RealField.C t, Dim.C u) =>
   Proc.T s u t
      (CausalD.T s (Sample.Flat t, SampleFrequency u t) (SamplePhase t))
phaseFreqMod =
   flip fmap (Proc.withParam toFrequencyScalar) $ \toFreq ->
   CausalD.consFlip $ \(Amp.Flat, Amp.Numeric freqAmp) ->
      (Amp.Abstract,
       Osci.phaseFreqMod <<< second (amplify (toFreq freqAmp)))