{-# LANGUAGE FlexibleContexts #-}
{- |
Copyright   :  (c) Henning Thielemann 2008-2011
License     :  GPL

Maintainer  :  synthesizer@henning-thielemann.de
Stability   :  provisional
Portability :  requires multi-parameter type classes
-}
module Synthesizer.Dimensional.Cyclic.Analysis (
    toFrequencySpectrum, fromFrequencySpectrum,
  ) where

import qualified Synthesizer.Generic.Fourier as FourierG
import qualified Synthesizer.Generic.Signal as SigG
import qualified Synthesizer.Generic.Cut as CutG

import qualified Synthesizer.Dimensional.Rate                 as Rate
import qualified Synthesizer.Dimensional.Amplitude            as Amp
import qualified Synthesizer.Dimensional.Signal.Private       as SigA
import qualified Synthesizer.Dimensional.Cyclic.Signal        as SigC

import qualified Number.DimensionTerm        as DN
import qualified Algebra.DimensionTerm       as Dim

import Number.DimensionTerm ((&*&), (*&), )

import qualified Number.Complex as Complex

import qualified Algebra.Transcendental      as Trans
import qualified Algebra.Field               as Field


import NumericPrelude.Base ((.), ($), )
import NumericPrelude.Numeric (fromIntegral, )
import Prelude ()


{- * Positions -}

{-# INLINE period #-}
period :: (Field.C t, Dim.C u, CutG.Read body) =>
   SigA.T (Rate.Dimensional u t) amp (SigC.T body) ->
   DN.T u t
period :: forall t u body amp.
(C t, C u, Read body) =>
T (Dimensional u t) amp (T body) -> T u t
period = forall t u body amp.
(C t, C u) =>
(body -> t) -> T (Dimensional u t) amp (T body) -> T u t
makePhysicalPeriod (forall a b. (C a, C b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall sig. Read sig => sig -> Int
CutG.length)

{-# INLINE makePhysicalPeriod #-}
makePhysicalPeriod :: (Field.C t, Dim.C u) =>
   (body -> t) ->
   SigA.T (Rate.Dimensional u t) amp (SigC.T body) ->
   DN.T u t
makePhysicalPeriod :: forall t u body amp.
(C t, C u) =>
(body -> t) -> T (Dimensional u t) amp (T body) -> T u t
makePhysicalPeriod body -> t
f T (Dimensional u t) amp (T body)
x =
   body -> t
f (forall period. T period -> period
SigC.toPeriod (forall rate amplitude body. T rate amplitude body -> body
SigA.body T (Dimensional u t) amp (T body)
x))
       forall u a. (C u, C a) => a -> T u a -> T u a
*&  forall u a. (C u, C a) => T (Recip u) a -> T u a
DN.unrecip (forall rate amp sig. T (Actual rate) amp sig -> rate
SigA.actualSampleRate T (Dimensional u t) amp (T body)
x)


{- |
Fourier analysis
-}
{-# INLINE toFrequencySpectrum #-}
toFrequencySpectrum ::
   (Trans.C q, Dim.C u, Dim.C v,
    SigG.Transform sig (Complex.T q)) =>
   SigA.T (Rate.Dimensional u q) (Amp.Dimensional v q) (SigC.T (sig (Complex.T q))) ->
   SigA.T (Rate.Dimensional (Dim.Recip u) q) (Amp.Dimensional (Dim.Mul u v) q) (SigC.T (sig (Complex.T q)))
toFrequencySpectrum :: forall q u v (sig :: * -> *).
(C q, C u, C v, Transform sig (T q)) =>
T (Dimensional u q) (Dimensional v q) (T (sig (T q)))
-> T (Dimensional (Recip u) q)
     (Dimensional (Mul u v) q)
     (T (sig (T q)))
toFrequencySpectrum T (Dimensional u q) (Dimensional v q) (T (sig (T q)))
x =
   let len :: T (Recip (Recip u)) q
len = forall u v a. (C u, C v) => (u -> v) -> T u a -> T v a
DN.rewriteDimension forall u. C u => u -> Recip (Recip u)
Dim.doubleRecip (forall t u body amp.
(C t, C u, Read body) =>
T (Dimensional u t) amp (T body) -> T u t
period T (Dimensional u q) (Dimensional v q) (T (sig (T q)))
x)
       amp :: T v q
amp = forall rate amp sig. T rate (Numeric amp) sig -> amp
SigA.actualAmplitude T (Dimensional u q) (Dimensional v q) (T (sig (T q)))
x
       newAmp :: T (Mul u v) q
newAmp = forall u a. (C u, C a) => T (Recip u) a -> T u a
DN.unrecip (forall rate amp sig. T (Actual rate) amp sig -> rate
SigA.actualSampleRate T (Dimensional u q) (Dimensional v q) (T (sig (T q)))
x) forall u v a. (C u, C v, C a) => T u a -> T v a -> T (Mul u v) a
&*& T v q
amp
   in  forall rate amplitude body.
rate -> amplitude -> body -> T rate amplitude body
SigA.Cons
          (forall rate. rate -> Actual rate
Rate.Actual T (Recip (Recip u)) q
len)
          (forall amp. amp -> Numeric amp
Amp.Numeric T (Mul u v) q
newAmp)
          (forall period. period -> T period
SigC.Cons forall a b. (a -> b) -> a -> b
$ forall y (sig :: * -> *).
(Element y, Transform sig y) =>
sig y -> sig y
FourierG.transformBackward forall a b. (a -> b) -> a -> b
$ forall period. T period -> period
SigC.toPeriod forall a b. (a -> b) -> a -> b
$ forall rate amplitude body. T rate amplitude body -> body
SigA.body T (Dimensional u q) (Dimensional v q) (T (sig (T q)))
x)
{-
toFrequencySpectrum $ SigP.Cons (DN.frequency (4::Prelude.Double)) (SigA.Cons (DN.voltage (1::Prelude.Double)) (SigC.Cons [1, 0 Number.Complex.+: (1::Prelude.Double), -1, 0 Number.Complex.+: (-1)]))
toFrequencySpectrum $ SigP.Cons (DN.frequency (4::Prelude.Double)) (SigA.Cons (DN.voltage (1::Prelude.Double)) (SigC.Cons [0 Number.Complex.+: (1::Prelude.Double), -1, 0 Number.Complex.+: (-1), 1]))
toFrequencySpectrum $ SigP.Cons (DN.frequency (4::Prelude.Double)) (SigA.Cons (DN.voltage (1::Prelude.Double)) (SigC.Cons [1, -1,1, (-1) Number.Complex.+: (0::Prelude.Double)]))
-}


{- |
Fourier synthesis
-}
{-# INLINE fromFrequencySpectrum #-}
fromFrequencySpectrum ::
   (Trans.C q, Dim.C u, Dim.C v,
    SigG.Transform sig (Complex.T q)) =>
   SigA.T (Rate.Dimensional (Dim.Recip u) q) (Amp.Dimensional (Dim.Mul u v) q) (SigC.T (sig (Complex.T q))) ->
   SigA.T (Rate.Dimensional u q) (Amp.Dimensional v q) (SigC.T (sig (Complex.T q)))
fromFrequencySpectrum :: forall q u v (sig :: * -> *).
(C q, C u, C v, Transform sig (T q)) =>
T (Dimensional (Recip u) q)
  (Dimensional (Mul u v) q)
  (T (sig (T q)))
-> T (Dimensional u q) (Dimensional v q) (T (sig (T q)))
fromFrequencySpectrum T (Dimensional (Recip u) q)
  (Dimensional (Mul u v) q)
  (T (sig (T q)))
x =
   let len :: T (Recip u) q
len = forall t u body amp.
(C t, C u, Read body) =>
T (Dimensional u t) amp (T body) -> T u t
period T (Dimensional (Recip u) q)
  (Dimensional (Mul u v) q)
  (T (sig (T q)))
x
       amp :: T (Mul u v) q
amp = forall rate amp sig. T rate (Numeric amp) sig -> amp
SigA.actualAmplitude T (Dimensional (Recip u) q)
  (Dimensional (Mul u v) q)
  (T (sig (T q)))
x
       newAmp :: T v q
newAmp =
          forall u v a. (C u, C v) => (u -> v) -> T u a -> T v a
DN.rewriteDimension
             (forall u. C u => Mul Scalar u -> u
Dim.identityLeft forall b c a. (b -> c) -> (a -> b) -> a -> c
.
              forall u0 u1 v.
(C u0, C u1, C v) =>
(u0 -> u1) -> Mul u0 v -> Mul u1 v
Dim.applyLeftMul forall u. C u => Mul (Recip u) u -> Scalar
Dim.cancelLeft forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall u0 u1 u2.
(C u0, C u1, C u2) =>
Mul u0 (Mul u1 u2) -> Mul (Mul u0 u1) u2
Dim.associateLeft)
             (forall u a. (C u, C a) => T (Recip u) a -> T u a
DN.unrecip (forall rate amp sig. T (Actual rate) amp sig -> rate
SigA.actualSampleRate T (Dimensional (Recip u) q)
  (Dimensional (Mul u v) q)
  (T (sig (T q)))
x) forall u v a. (C u, C v, C a) => T u a -> T v a -> T (Mul u v) a
&*& T (Mul u v) q
amp)
   in  forall rate amplitude body.
rate -> amplitude -> body -> T rate amplitude body
SigA.Cons
          (forall rate. rate -> Actual rate
Rate.Actual T (Recip u) q
len)
          (forall amp. amp -> Numeric amp
Amp.Numeric T v q
newAmp)
          (forall period. period -> T period
SigC.Cons forall a b. (a -> b) -> a -> b
$ forall y (sig :: * -> *).
(Element y, Transform sig y) =>
sig y -> sig y
FourierG.transformForward forall a b. (a -> b) -> a -> b
$ forall period. T period -> period
SigC.toPeriod forall a b. (a -> b) -> a -> b
$ forall rate amplitude body. T rate amplitude body -> body
SigA.body T (Dimensional (Recip u) q)
  (Dimensional (Mul u v) q)
  (T (sig (T q)))
x)