{- |
Copyright   :  (c) Henning Thielemann 2008
License     :  GPL

Maintainer  :  synthesizer@henning-thielemann.de
Stability   :  provisional
Portability :  requires multi-parameter type classes
-}
module Synthesizer.Dimensional.Amplitude.Filter (
   {- * Non-recursive -}

   {- ** Amplification -}
   amplify,
   amplifyDimension,
   negate,
   envelope,
   envelopeVector,
   envelopeVectorDimension,
 ) where


import qualified Synthesizer.Dimensional.Abstraction.RateIndependent as Ind
import qualified Synthesizer.Dimensional.Abstraction.Homogeneous as Hom
import qualified Synthesizer.Dimensional.Abstraction.Flat as Flat

import qualified Synthesizer.Dimensional.RatePhantom as RP

-- import qualified Synthesizer.Dimensional.Straight.Signal      as SigS
import qualified Synthesizer.Dimensional.Amplitude.Signal as SigA
-- import Synthesizer.Dimensional.Amplitude.Signal (toAmplitudeScalar)

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

import Number.DimensionTerm ((&*&))

-- import qualified Synthesizer.State.Signal              as Sig
import qualified Synthesizer.State.Filter.NonRecursive as FiltNR

-- import qualified Algebra.Transcendental as Trans
-- import qualified Algebra.Field          as Field
import qualified Algebra.Ring           as Ring
import qualified Algebra.Additive       as Additive
import qualified Algebra.Module         as Module

-- import NumericPrelude hiding (negate)
-- import PreludeBase as P
import Prelude (($))


{- | The amplification factor must be positive. -}
{-# INLINE amplify #-}
amplify :: (Ind.C w, Ring.C y, Dim.C u) =>
      y
   -> w (SigA.S u y) yv
   -> w (SigA.S u y) yv
amplify volume x =
   SigA.replaceAmplitude (DN.scale volume $ SigA.amplitude x) x

{-# INLINE amplifyDimension #-}
amplifyDimension :: (Ind.C w, Ring.C y, Dim.C u, Dim.C v) =>
      DN.T v y
   -> w (SigA.S u y) yv
   -> w (SigA.S (Dim.Mul v u) y) yv
amplifyDimension volume x =
   SigA.replaceAmplitude (volume &*& SigA.amplitude x) x

-- FIXME: move to Dimensional.Straight
{-# INLINE negate #-}
negate :: (Ind.C w, Hom.C sig, Additive.C yv) =>
      w sig yv
   -> w sig yv
negate =
   Ind.processSignal (Hom.unwrappedProcessSamples Additive.negate)

-- FIXME: move to Dimensional.Straight
{-# INLINE envelope #-}
envelope :: (Hom.C sig, Flat.C flat y0, Ring.C y0) =>
      RP.T s flat y0   {- ^ the envelope -}
   -> RP.T s sig y0    {- ^ the signal to be enveloped -}
   -> RP.T s sig y0
envelope y =
   Hom.processSamples (FiltNR.envelope (Flat.toSamples y))

-- FIXME: move to Dimensional.Straight
{-# INLINE envelopeVector #-}
envelopeVector :: (Hom.C sig, Flat.C flat y0, Module.C y0 yv) =>
      RP.T s flat y0   {- ^ the envelope -}
   -> RP.T s sig yv    {- ^ the signal to be enveloped -}
   -> RP.T s sig yv
envelopeVector y =
   Hom.processSamples (FiltNR.envelopeVector (Flat.toSamples y))

{-# INLINE envelopeVectorDimension #-}
envelopeVectorDimension :: (Module.C y0 yv, Ring.C y, Dim.C u, Dim.C v) =>
      SigA.R s v y y0  {- ^ the envelope -}
   -> SigA.R s u y yv  {- ^ the signal to be enveloped -}
   -> SigA.R s (Dim.Mul v u) y yv
envelopeVectorDimension y x =
   SigA.fromSamples
      (SigA.amplitude y &*& SigA.amplitude x)
      (FiltNR.envelopeVector (SigA.samples y) (SigA.samples x))