synthesizer-dimensional-0.5.1: src/Synthesizer/Dimensional/Cyclic/Analysis.hs
{-# 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 = makePhysicalPeriod (fromIntegral . 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 f x =
f (SigC.toPeriod (SigA.body x))
*& DN.unrecip (SigA.actualSampleRate 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 x =
let len = DN.rewriteDimension Dim.doubleRecip (period x)
amp = SigA.actualAmplitude x
newAmp = DN.unrecip (SigA.actualSampleRate x) &*& amp
in SigA.Cons
(Rate.Actual len)
(Amp.Numeric newAmp)
(SigC.Cons $ FourierG.transformBackward $ SigC.toPeriod $ SigA.body 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 x =
let len = period x
amp = SigA.actualAmplitude x
newAmp =
DN.rewriteDimension
(Dim.identityLeft .
Dim.applyLeftMul Dim.cancelLeft . Dim.associateLeft)
(DN.unrecip (SigA.actualSampleRate x) &*& amp)
in SigA.Cons
(Rate.Actual len)
(Amp.Numeric newAmp)
(SigC.Cons $ FourierG.transformForward $ SigC.toPeriod $ SigA.body x)