module Synthesizer.Dimensional.RateAmplitude.Piece ( {- * Piecewise -} step, linear, exponential, cosine, halfSine, cubic, T, Sequence, run, runVolume, runState, runStateVolume, (-|#), ( #|-), (=|#), ( #|=), (|#), ( #|), -- spaces before # for Haddock Piece.FlatPosition(..), ) where import qualified Synthesizer.Generic.Piece as Piece import qualified Synthesizer.Generic.Signal as SigG import qualified Synthesizer.Generic.Cut as CutG import qualified Synthesizer.State.Control as Ctrl import qualified Synthesizer.Piecewise as Piecewise import Synthesizer.Piecewise ((-|#), ( #|-), (=|#), ( #|=), (|#), ( #|), ) import qualified Synthesizer.Dimensional.Signal.Private as SigA import qualified Synthesizer.Dimensional.Process as Proc import Synthesizer.Dimensional.Process (toTimeScalar, toGradientScalar, DimensionGradient, ) -- import Synthesizer.Dimensional.Process (($:), ($#), ) import qualified Synthesizer.Dimensional.Amplitude as Amp import qualified Synthesizer.Dimensional.Rate as Rate import qualified Synthesizer.State.Signal as Sig import qualified Number.DimensionTerm as DN import qualified Algebra.DimensionTerm as Dim -- import Number.DimensionTerm ((&*&)) -- import qualified Algebra.Module as Module import qualified Algebra.Transcendental as Trans import qualified Algebra.RealField as RealField import qualified Algebra.Field as Field -- import qualified Algebra.Real as Real -- import qualified Algebra.Ring as Ring -- import qualified Algebra.Additive as Additive -- import Control.Monad.Fix (mfix, ) import Control.Monad (liftM3, ) import NumericPrelude (zero, ) import PreludeBase import Prelude () type T s u v sig q = Piecewise.Piece (DN.T u q) (DN.T v q) (DN.T v q -> SigG.LazySize -> q -> Proc.T s u q (SigA.T (Rate.Phantom s) (Amp.Flat q) (sig q))) type Sequence s u v sig q = Piecewise.T (DN.T u q) (DN.T v q) (DN.T v q -> SigG.LazySize -> q -> Proc.T s u q (SigA.T (Rate.Phantom s) (Amp.Flat q) (sig q))) {- | Since this function looks for the maximum node value, and since the signal parameter inference phase must be completed before signal processing, infinite descriptions cannot be used here. -} {-# INLINE run #-} run :: (Trans.C q, RealField.C q, Dim.C u, Dim.C v, SigG.Write sig q) => DN.T u q -> Sequence s u v sig q -> Proc.T s u q (SigA.T (Rate.Phantom s) (Amp.Dimensional v q) (sig q)) run lazySize cs = runVolume lazySize cs $ maximum $ map (\c -> max (DN.abs (Piecewise.pieceY0 c)) (DN.abs (Piecewise.pieceY1 c))) cs {-# INLINE runVolume #-} runVolume :: (Trans.C q, RealField.C q, Dim.C u, Dim.C v, SigG.Write sig q) => DN.T u q -> Sequence s u v sig q -> DN.T v q -> Proc.T s u q (SigA.T (Rate.Phantom s) (Amp.Dimensional v q) (sig q)) runVolume lazySize' cs amplitude = -- it would be nice if we could re-use Ctrl.piecewise do ts0 <- mapM (toTimeScalar . Piecewise.pieceDur) cs lazySize <- Proc.intFromTime "Dimensional.Piece.runVolume" lazySize' fmap (SigA.fromBody amplitude . SigG.concat) $ sequence $ zipWith (\(n,t) (Piecewise.PieceData c yi0 yi1 d) -> fmap (SigG.take n . SigA.body) $ Piecewise.computePiece c yi0 yi1 d amplitude (SigG.LazySize lazySize) t) (Ctrl.splitDurations ts0) cs {-# INLINE runState #-} runState :: (Trans.C q, RealField.C q, Dim.C u, Dim.C v) => Sequence s u v Sig.T q -> Proc.T s u q (SigA.R s v q q) runState = run zero {-# INLINE runStateVolume #-} runStateVolume :: (Trans.C q, RealField.C q, Dim.C u, Dim.C v) => Sequence s u v Sig.T q -> DN.T v q -> Proc.T s u q (SigA.R s v q q) runStateVolume = runVolume zero {-# INLINE toAmpScalar #-} toAmpScalar :: (Field.C a, Dim.C u) => DN.T u a -> DN.T u a -> a toAmpScalar amp y = DN.divToScalar y amp {-# INLINE make #-} make :: (Field.C q, Dim.C u, Dim.C v, SigG.Write sig q) => Piece.T sig q -> T s u v sig q make piece = Piecewise.pieceFromFunction $ \ y0 y1 d amplitude lazySize t0 -> flip fmap (toTimeScalar d) (\d' -> SigA.flatFromBody $ Piecewise.computePiece piece (toAmpScalar amplitude y0) (toAmpScalar amplitude y1) d' lazySize t0) {-# INLINE step #-} step :: (Field.C q, Dim.C u, Dim.C v, SigG.Write sig q) => T s u v sig q step = make Piece.step {-# INLINE linear #-} linear :: (Field.C q, Dim.C u, Dim.C v, SigG.Write sig q) => T s u v sig q linear = make Piece.linear {-# INLINE exponential #-} exponential :: (Trans.C q, Dim.C u, Dim.C v, SigG.Write sig q) => DN.T v q -> T s u v sig q exponential saturation = Piecewise.pieceFromFunction $ \ y0 y1 d amplitude lazySize t0 -> flip fmap (toTimeScalar d) (\d' -> SigA.flatFromBody $ Piecewise.computePiece (Piece.exponential (toAmpScalar amplitude saturation)) (toAmpScalar amplitude y0) (toAmpScalar amplitude y1) d' lazySize t0) {-# INLINE cosine #-} cosine :: (Trans.C q, Dim.C u, Dim.C v, SigG.Write sig q) => T s u v sig q cosine = make Piece.cosine {-# INLINE halfSine #-} halfSine :: (Trans.C q, Dim.C u, Dim.C v, SigG.Write sig q) => Piece.FlatPosition -> T s u v sig q halfSine pos = make (Piece.halfSine pos) {-# INLINE cubic #-} cubic :: (Field.C q, Dim.C u, Dim.C v, SigG.Write sig q) => DN.T (DimensionGradient u v) q -> DN.T (DimensionGradient u v) q -> T s u v sig q cubic yd0 yd1 = Piecewise.pieceFromFunction $ \ y0 y1 d amplitude lazySize t0 -> liftM3 (\d' yd0' yd1' -> SigA.flatFromBody $ Piecewise.computePiece (Piece.cubic yd0' yd1') (toAmpScalar amplitude y0) (toAmpScalar amplitude y1) d' lazySize t0) (toTimeScalar d) (toGradientScalar amplitude yd0) (toGradientScalar amplitude yd1)