synthesizer-dimensional-0.4: src/Synthesizer/Dimensional/Amplitude/Flat.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{- |
Copyright : (c) Henning Thielemann 2008-2009
License : GPL
Maintainer : synthesizer@henning-thielemann.de
Stability : provisional
Portability : requires multi-parameter type classes
A class that allows unified handling of
@Amplitude.Flat@ and @Amplitude.Dimensional Dim.Scalar@
which is often used for control curves.
However, I'm thinking about whether this is more abuse than use.
So this class may disappear in future.
Amplitude.Flat might become a synonym for @DN.scalar one@.
Sometimes, using Flat instead of DN.Scalar has the advantage
of internally saving a multiplication with one,
but I think the compiler should optimize that away.
The optimization however is more complicated
if a whole StorableVector is multiplied element-wise by one.
E.g. the concatenation of flat (storable) signals
can be done without copying the entire data.
-}
module Synthesizer.Dimensional.Amplitude.Flat
(C, amplifySample, canonicalize, toSamples, ) where
import qualified Synthesizer.Dimensional.Amplitude as Amp
import qualified Synthesizer.Dimensional.Signal.Private as SigA
import qualified Synthesizer.Generic.Filter.NonRecursive as FiltG
import qualified Synthesizer.Generic.Signal as SigG
-- import qualified Synthesizer.State.Signal as Sig
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
import Prelude ()
{-
we could use OccasionallyScalar class,
but this would flood user code with OccScalar.C y y constraints
-}
class Amp.C amp => C y amp | amp -> y where
toScalar :: amp -> y
amplifySample :: amp -> y -> y
amplify :: (SigG.Transform sig y) =>
amp -> sig y -> sig y
instance Ring.C y => C y (Amp.Flat y) where
toScalar = const Ring.one
amplifySample _ = id
amplify _ = id
instance (Dim.IsScalar v, Ring.C y) => C y (Amp.Numeric (DN.T v y)) where
toScalar (Amp.Numeric amp) =
DN.toNumber .
DN.rewriteDimension Dim.toScalar $
amp
amplifySample amp y = toScalar amp * y
amplify amp = FiltG.amplify (toScalar amp)
{- DEPRECATED toSamples "this function drops the sample rate, better use canonicalize" -}
{-# INLINE toSamples #-}
toSamples ::
(C y flat, SigG.Transform sig y) =>
SigA.T rate flat (sig y) -> sig y
toSamples sig =
amplify (SigA.amplitude sig) (SigA.body sig)
{-# INLINE canonicalize #-}
canonicalize ::
(C y flat, SigG.Transform sig y) =>
SigA.T rate flat (sig y) -> SigA.T rate (Amp.Flat y) (sig y)
canonicalize sig =
SigA.Cons (SigA.sampleRate sig) Amp.Flat (toSamples sig)