{-# 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)