synthesizer-dimensional-0.2: src/Synthesizer/Dimensional/Amplitude/Signal.hs
{- |
Copyright : (c) Henning Thielemann 2008
License : GPL
Maintainer : synthesizer@henning-thielemann.de
Stability : provisional
Portability : requires multi-parameter type classes
Signals equipped with a volume information that may carry a unit.
Is the approach with separated volume information still appropriate?
Actually it simplifies reusing code from "Synthesizer.State.Signal"
because we do not have to replace @(*)@ by @(&*&)@.
-}
module Synthesizer.Dimensional.Amplitude.Signal where
import qualified Synthesizer.Dimensional.Amplitude as Amp
import qualified Synthesizer.Format as Format
import qualified Synthesizer.Dimensional.Abstraction.RateIndependent as Ind
import qualified Synthesizer.Dimensional.RatePhantom as RP
import qualified Synthesizer.Dimensional.Straight.Signal as SigS
import qualified Synthesizer.State.Filter.NonRecursive as Filt
import qualified Synthesizer.State.Signal as Sig
import qualified Synthesizer.Generic.Filter.NonRecursive as FiltG
import qualified Synthesizer.Generic.Signal as SigG
import qualified Number.DimensionTerm as DN
import qualified Algebra.DimensionTerm as Dim
import qualified Algebra.Module as Module
import qualified Algebra.Field as Field
import qualified Algebra.Ring as Ring
-- import Number.DimensionTerm ((&/&))
import NumericPrelude
import PreludeBase as P
import Prelude ()
data T amp sig yv =
Cons {
privateAmplitude :: amp {-^ scaling of the values -}
, signal :: sig yv {-^ the embedded signal -}
}
-- deriving (Eq, Show)
instance (Show amp, Format.C sig) => Format.C (T amp sig) where
format p (Cons amp sig) =
showParen (p >= 10)
(showString "amplitudeSignal " . showsPrec 11 amp .
showString " " . Format.format 11 sig)
instance (Show amp, Show yv, Format.C sig) => Show (T amp sig yv) where
showsPrec = Format.format
type R s v y yv = RP.T s (S v y) yv
type S v y = D v y SigS.S -- kind * -> *
type D v y = T (DN.T v y)
{-
We removed that instance because 'fmap' is too dangerous for application code.
You may write functions that depend on the particular amplitude scaling.
instance Dim.C v => Functor (D v y s) where
fmap f (Cons amp ss) = Cons amp (map f ss)
-}
{-# INLINE amplitude #-}
amplitude :: (Ind.C w, Dim.C v) =>
w (D v y sig) yv -> DN.T v y
amplitude = privateAmplitude . Ind.toSignal
{-# INLINE samples #-}
samples :: (Ind.C w, Dim.C v) =>
w (D v y (SigS.T sig)) yv -> sig yv
samples = privateSamples . Ind.toSignal
{-# INLINE privateSamples #-}
privateSamples :: (Amp.C amp) =>
T amp (SigS.T sig) yv -> sig yv
privateSamples = SigS.samples . signal
{-# INLINE phantomSignal #-}
phantomSignal ::
RP.T s (D v y sig) yv -> RP.T s sig yv
phantomSignal =
RP.fromSignal . signal . RP.toSignal
{-# INLINE toAmplitudeScalar #-}
toAmplitudeScalar :: (Ind.C w, Field.C y, Dim.C v) =>
w (D v y sig) yv -> DN.T v y -> y
toAmplitudeScalar sig y =
DN.divToScalar y (amplitude sig)
{-# INLINE scalarSamples #-}
{-
scalarSamples :: (Ind.C w, Ring.C y, Dim.C v) =>
(DN.T v y -> y) -> w (S v y) y -> Sig.T y
-}
scalarSamples :: (Ind.C w, Ring.C y, Amp.C amp) =>
(amp -> y) -> w (T amp SigS.S) y -> Sig.T y
scalarSamples toAmpScalar =
scalarSamplesPrivate toAmpScalar . Ind.toSignal
{-# INLINE scalarSamplesGeneric #-}
scalarSamplesGeneric ::
(Ind.C w, Ring.C y, Dim.C v, SigG.Transform sig y) =>
(DN.T v y -> y) -> w (D v y (SigS.T sig)) y -> sig y
scalarSamplesGeneric toAmpScalar =
scalarSamplesPrivateGeneric toAmpScalar . Ind.toSignal
{-# INLINE vectorSamples #-}
vectorSamples :: (Ind.C w, Module.C y yv, Dim.C v) =>
(DN.T v y -> y) -> w (S v y) yv -> Sig.T yv
vectorSamples toAmpScalar =
vectorSamplesPrivate toAmpScalar . Ind.toSignal
{-# INLINE rewriteDimension #-}
rewriteDimension :: (Dim.C v0, Dim.C v1) =>
(v0 -> v1) -> D v0 y sig yv -> D v1 y sig yv
rewriteDimension f (Cons amp ss) =
Cons (DN.rewriteDimension f amp) ss
{-# INLINE fromSignal #-}
-- fromSignal :: DN.T v y -> SigS.R s yv -> R s v y yv
fromSignal :: amp -> SigS.R s yv -> RP.T s (T amp SigS.S) yv
fromSignal amp = RP.fromSignal . Cons amp . RP.toSignal
{-# INLINE toScalarSignal #-}
toScalarSignal :: (Ind.C w, Field.C y, Dim.C v) =>
DN.T v y -> w (S v y) y -> w SigS.S y
toScalarSignal amp =
Ind.processSignal
(SigS.Cons . scalarSamplesPrivate (flip DN.divToScalar amp))
{-# INLINE toVectorSignal #-}
toVectorSignal :: (Ind.C w, Field.C y, Module.C y yv, Dim.C v) =>
DN.T v y -> w (S v y) yv -> w SigS.S yv
toVectorSignal amp =
Ind.processSignal
(SigS.Cons . vectorSamplesPrivate (flip DN.divToScalar amp))
{-# INLINE scalarSamplesPrivate #-}
{-
scalarSamplesPrivate :: (Ring.C y, Dim.C v) =>
(DN.T v y -> y) -> S v y y -> Sig.T y
-}
scalarSamplesPrivate :: (Ring.C y, Amp.C amp) =>
(amp -> y) -> T amp SigS.S y -> Sig.T y
scalarSamplesPrivate toAmpScalar sig =
let y = toAmpScalar (privateAmplitude sig)
in Filt.amplify y (privateSamples sig)
{-# INLINE scalarSamplesPrivateGeneric #-}
scalarSamplesPrivateGeneric ::
(Ring.C y, Dim.C v, SigG.Transform sig y) =>
(DN.T v y -> y) -> D v y (SigS.T sig) y -> sig y
scalarSamplesPrivateGeneric toAmpScalar sig =
let y = toAmpScalar (privateAmplitude sig)
in FiltG.amplify y (privateSamples sig)
{-# INLINE vectorSamplesPrivate #-}
vectorSamplesPrivate :: (Module.C y yv, Dim.C v) =>
(DN.T v y -> y) -> S v y yv -> Sig.T yv
vectorSamplesPrivate toAmpScalar sig =
let y = toAmpScalar (privateAmplitude sig)
in y *> privateSamples sig
{-# INLINE fromSamples #-}
-- fromSamples :: (Dim.C v) => DN.T v y -> Sig.T yv -> R s v y yv
fromSamples :: {- (Amp.C amp) => -} amp -> Sig.T yv -> RP.T s (T amp SigS.S) yv
fromSamples amp = fromSignal amp . SigS.fromSamples
{-# INLINE fromScalarSamples #-}
fromScalarSamples :: {- (Amp.C amp) => -}
amp -> Sig.T y -> RP.T s (T amp SigS.S) y
fromScalarSamples = fromSamples
{-# INLINE fromVectorSamples #-}
fromVectorSamples :: {- (Amp.C amp) => -}
amp -> Sig.T yv -> RP.T s (T amp SigS.S) yv
fromVectorSamples = fromSamples
{-# INLINE replaceAmplitude #-}
replaceAmplitude :: (Ind.C w, Dim.C v0, Dim.C v1) =>
DN.T v1 y -> w (D v0 y sig) yv -> w (D v1 y sig) yv
replaceAmplitude amp = Ind.processSignal (replaceAmplitudePrivate amp)
{-# INLINE replaceSamples #-}
replaceSamples :: (Ind.C w, Dim.C v) =>
sig1 yv1 -> w (D v y sig0) yv0 -> w (D v y (SigS.T sig1)) yv1
replaceSamples ss = Ind.processSignal (replaceSamplesPrivate ss)
{-# INLINE replaceAmplitudePrivate #-}
replaceAmplitudePrivate :: (Dim.C v0, Dim.C v1) =>
DN.T v1 y -> D v0 y sig yv -> D v1 y sig yv
replaceAmplitudePrivate amp = Cons amp . signal
{-# INLINE replaceSamplesPrivate #-}
replaceSamplesPrivate :: (Dim.C v) =>
sig1 yv1 -> D v y sig0 yv0 -> D v y (SigS.T sig1) yv1
replaceSamplesPrivate ss x = Cons (privateAmplitude x) (SigS.Cons ss)
{-# INLINE processSamples #-}
processSamples :: (Ind.C w, Dim.C v) =>
(sig0 yv0 -> sig1 yv1) ->
w (D v y (SigS.T sig0)) yv0 -> w (D v y (SigS.T sig1)) yv1
processSamples f =
Ind.processSignal (processSamplesPrivate f)
{-# INLINE processSamplesPrivate #-}
processSamplesPrivate :: (Dim.C v) =>
(sig0 yv0 -> sig1 yv1) ->
D v y (SigS.T sig0) yv0 -> D v y (SigS.T sig1) yv1
processSamplesPrivate f (Cons amp sig) =
Cons amp (SigS.processSamplesPrivate f sig)
{-# INLINE asTypeOfAmplitude #-}
asTypeOfAmplitude :: y -> w (D v y sig) yv -> y
asTypeOfAmplitude = const