packages feed

synthesizer-core 0.2 → 0.2.1

raw patch · 22 files changed

+875/−54 lines, 22 filesdep +storable-tupledep ~numeric-preludedep ~storablevector

Dependencies added: storable-tuple

Dependency ranges changed: numeric-prelude, storablevector

Files

src/Synthesizer/ApplicativeUtility.hs view
@@ -1,7 +1,7 @@ -- this is also used by synthesizer-dimensional and synthesizer-inference module Synthesizer.ApplicativeUtility where -import Control.Applicative (Applicative, pure, (<*>), (<$>), liftA2, )+import Control.Applicative (Applicative, (<*>), (<$>), liftA2, ) import Data.Traversable (Traversable, sequenceA, )  import Control.Monad.Fix (fix, )@@ -73,9 +73,9 @@ -- (.^) f = (.:) (pure f)  {-# INLINE ($#) #-}-($#) :: (Applicative f) => f (a -> b) -> a -> f b-($#) f x = f $: pure x--- ($#) = flip+($#) :: (Functor f) => f (a -> b) -> a -> f b+($#) f x = fmap ($x) f+-- ($#) f x = f $: pure x   {- |
src/Synthesizer/Causal/ToneModulation.hs view
@@ -129,7 +129,7 @@ {- ToDo: Both lengthAtMost and dropMarginRem seek through the list. Maybe an improved version of dropMargin could avoid this.-E.g. dropMarginRem :: dropMarginRem :: Int -> Int -> sig y -> (Maybe Int, sig y),+E.g. dropMarginRem :: Int -> Int -> sig y -> (Maybe Int, sig y), where return value (Just 0) means, that drop could actually drop the requested number of elements, but that we reached the end of the list.
src/Synthesizer/Filter/Basic.hs view
@@ -12,7 +12,7 @@ import NumericPrelude import PreludeBase -{- todo:+{- ToDo:     - support of data before time 0        - the problem is that all past data has to be kept,          the garbage collector can't flush it :-(
src/Synthesizer/Filter/Composition.hs view
@@ -19,7 +19,7 @@ import PreludeBase import NumericPrelude -{- todo:+{- ToDo:     - functions that build a FilterComposition for specific filters         (1st order, universal, allpass, butterworth, chebyshev)     - functions that turn physical filter parameters into
src/Synthesizer/Frame/Stereo.hs view
@@ -8,14 +8,23 @@ import qualified Sound.Sox.Frame as Frame  import qualified Synthesizer.Interpolation.Class as Interpol-import qualified Algebra.Module   as Module-import qualified Algebra.Additive as Additive +import qualified Algebra.NormedSpace.Maximum   as NormedMax+import qualified Algebra.NormedSpace.Euclidean as NormedEuc+import qualified Algebra.NormedSpace.Sum       as NormedSum++import qualified Algebra.Module    as Module+import qualified Algebra.Algebraic as Algebraic+import qualified Algebra.Additive  as Additive+ import Foreign.Storable (Storable (..), ) import qualified Foreign.Storable.Record as Store  import Control.Applicative (liftA2, )+import Control.Monad (liftM2, ) +import Test.QuickCheck (Arbitrary(..), )+ import NumericPrelude import PreludeBase hiding (map) import Prelude ()@@ -24,8 +33,20 @@  -- cf. Sound.Sox.Frame.Stereo data T a = Cons {left, right :: !a}+   deriving (Eq)  +instance Show a => Show (T a) where+   showsPrec p x =+      showParen (p >= 10)+         (showString "Stereo.cons " . showsPrec 11 (left x) .+          showString " " . showsPrec 11 (right x))++instance (Arbitrary a) => Arbitrary (T a) where+   arbitrary = liftM2 cons arbitrary arbitrary+   coarbitrary = error "Stereo.coarbitrary not implemented"++ {-# INLINE cons #-} cons :: a -> a -> T a cons = Cons@@ -62,14 +83,30 @@    (-)    (Cons xl xr) (Cons yl yr) = Cons (xl-yl) (xr-yr)    negate (Cons xl xr)              = Cons (negate xl) (negate xr) -instance (Module.C a b) => Module.C a (T b) where+instance (Module.C a v) => Module.C a (T v) where    {-# INLINE (*>) #-}    s *> (Cons l r)   = Cons (s *> l) (s *> r) -instance Interpol.C a b => Interpol.C a (T b) where+instance Interpol.C a v => Interpol.C a (T v) where    {-# INLINE scaleAndAccumulate #-}    scaleAndAccumulate =       Interpol.makeMac2 Cons left right+++instance (Additive.C a, NormedSum.C a v) => NormedSum.C a (T v) where+   norm (Cons l r) =+      NormedSum.norm l + NormedSum.norm r++instance (NormedEuc.Sqr a v) => NormedEuc.Sqr a (T v) where+   normSqr (Cons l r) =+      NormedEuc.normSqr l + NormedEuc.normSqr r++instance (Algebraic.C a, NormedEuc.Sqr a v) => NormedEuc.C a (T v) where+   norm = NormedEuc.defltNorm++instance (Ord a, NormedMax.C a v) => NormedMax.C a (T v) where+   norm (Cons l r) =+      max (NormedMax.norm l) (NormedMax.norm r)   instance Frame.C a => Frame.C (T a) where
src/Synthesizer/FusionList/Control.hs view
@@ -16,6 +16,7 @@  -- import Synthesizer.FusionList.Displacement (raise) import qualified Synthesizer.FusionList.Signal as Sig+import Synthesizer.State.Control (splitDurations, )  import qualified Algebra.Module                as Module import qualified Algebra.Transcendental        as Trans@@ -175,15 +176,7 @@ -- * piecewise curves  -splitDurations :: (RealField.C t) =>-   [t] -> [(Int, t)]-splitDurations ts0 =-   let (ds,ts) =-           unzip $ scanl-              (\(_,fr) d -> splitFraction (fr+d))-              (0,1) ts0-   in  zip (tail ds) (map (subtract 1) ts)-+{-# DEPRECATED Piece, piecewise "use Synthesizer.Generic.Piece instead" #-} {-# INLINE piecewise #-} piecewise :: (RealField.C a) =>    Piecewise.T a a (a -> Sig.T a) -> Sig.T a
src/Synthesizer/Generic/Control.hs view
@@ -217,6 +217,7 @@   +{-# DEPRECATED Control "use Synthesizer.Generic.Piece instead" #-} {- | The curve type of a piece of a piecewise defined control curve. -}
src/Synthesizer/Generic/Filter/NonRecursive.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE FlexibleContexts #-} {- |-Copyright   :  (c) Henning Thielemann 2008+Copyright   :  (c) Henning Thielemann 2008-2009 License     :  GPL  Maintainer  :  synthesizer@henning-thielemann.de@@ -10,8 +11,11 @@ module Synthesizer.Generic.Filter.NonRecursive where  import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Generic.Signal2 as SigG2  import qualified Synthesizer.Generic.Control as Ctrl+import qualified Synthesizer.State.Signal as SigS+import qualified Synthesizer.Plain.Filter.NonRecursive as Filt  import qualified Algebra.Transcendental as Trans import qualified Algebra.Module         as Module@@ -23,10 +27,10 @@ import Algebra.Module( {- linearComb, -} (*>), )  import Data.Function.HT (nest, )+import Data.Tuple.HT (mapSnd, mapPair, )  import PreludeBase-import NumericPrelude-+import NumericPrelude as NP   {- * Envelope application -}@@ -240,16 +244,25 @@ sums n = SigG.mapTails (SigG.sum . SigG.take n)  -{--sumsDownsample2 :: (Additive.C v) => sig v -> sig v-sumsDownsample2 (x0:x1:xs) = (x0+x1) : sumsDownsample2 xs-sumsDownsample2 xs         = xs+sumsDownsample2 ::+   (Additive.C v, SigG.Write sig v) =>+   SigG.LazySize -> sig v -> sig v+sumsDownsample2 cs =+   SigG.unfoldR cs (\xs ->+      flip fmap (SigG.viewL xs) $ \xxs0@(x0,xs0) ->+         SigG.switchL xxs0 {- xs0 is empty -}+            (\ x1 xs1 -> (x0+x1, xs1))+            xs0) -downsample2 :: sig a -> sig a-downsample2 (x0:_:xs) = x0 : downsample2 xs-downsample2 xs        = xs+downsample2 ::+   (SigG.Write sig v) =>+   SigG.LazySize -> sig v -> sig v+downsample2 cs =+   SigG.unfoldR cs+      (fmap (mapSnd SigG.laxTail) . SigG.viewL)  +{- {- | Given a list of numbers and a list of sums of (2*k) of successive summands,@@ -305,6 +318,96 @@          zipWith3 (\x y z -> x==y && y==z) naive rec pyramid  -}++sumRange ::+   (Additive.C v, SigG.Transform sig v) =>+   sig v -> (Int,Int) -> v+sumRange =+   Filt.sumRangePrepare $ \ (l,r) ->+   SigG.sum . SigG.take (r-l) . SigG.drop l++pyramid ::+   (Additive.C v, SigG.Write sig v) =>+   Int -> sig v -> ([Int], [sig v])+pyramid height sig =+   let sizes =+          reverse $ take (1+height) $ iterate (2*) 1+   in  (sizes,+        scanl (flip sumsDownsample2) sig (map SigG.LazySize $ tail sizes))++sumRangeFromPyramid ::+   (Additive.C v, SigG.Write sig v) =>+   [sig v] -> (Int,Int) -> v+sumRangeFromPyramid =+   Filt.sumRangePrepare $ \(l0,r0) pyr0 ->+   case pyr0 of+      [] -> error "empty pyramid"+      (ps0:pss) ->+         foldr+            (\psNext k (l,r) ps s ->+               case r-l of+                  0 -> s+                  1 -> s + SigG.index ps l+                  _ ->+                     let (lh,ll) = NP.negate $ divMod (NP.negate l) 2+                         (rh,rl) = divMod r 2+                         {-# INLINE inc #-}+                         inc b x = if b==0 then id else (x+)+                     in  k (lh,rh) psNext $+                         inc ll (SigG.index ps l) $+                         inc rl (SigG.index ps (r-1)) $+                         s)+            (\(l,r) ps s ->+               s + (SigG.sum $ SigG.take (r-l) $ SigG.drop l ps))+            pss (l0,r0) ps0 zero++sumsPosModulated ::+   (Additive.C v, SigG2.Transform sig (Int,Int) v) =>+   sig (Int,Int) -> sig v -> sig v+sumsPosModulated ctrl xs =+   SigG2.zipWithTails (flip sumRange) ctrl xs+++{- |+Moving average, where window bounds must be always non-negative.++The laziness granularity is @2^height@.+-}+sumsPosModulatedPyramid ::+   (Additive.C v, SigG.Transform sig (Int,Int), SigG.Write sig v) =>+   Int -> sig (Int,Int) -> sig v -> sig v+sumsPosModulatedPyramid height ctrl xs =+   let (sizes,pyr0) = pyramid height xs+       blockSize = head sizes+       pyrStarts =+          iterate (zipWith SigG.drop sizes) pyr0+       ctrlBlocks =+          SigS.toList $+          SigG.sliceVertical blockSize ctrl+   in  SigG.concat $+       zipWith+          (\pyr ->+              SigG.fromState (SigG.LazySize blockSize) .+              SigS.map (sumRangeFromPyramid pyr) .+              SigS.zipWith (\d -> mapPair ((d+), (d+))) (SigS.iterate (1+) 0) .+              SigG.toState)+          pyrStarts ctrlBlocks++{- |+The first argument is the amplification.+The main reason to introduce it,+was to have only a Module constraint instead of Field.+This way we can also filter stereo signals.+-}+movingAverageModulatedPyramid ::+   (Field.C a, Module.C a v,+    SigG2.Transform sig Int (Int,Int), SigG.Write sig v) =>+   a -> Int -> Int -> sig Int -> sig v -> sig v+movingAverageModulatedPyramid amp height maxC ctrl xs =+   SigG.zipWith (\c x -> (amp / fromIntegral (2*c+1)) *> x) ctrl $+   sumsPosModulatedPyramid height+      (SigG2.map (\c -> (maxC - c, maxC + c)) ctrl)+      (delay maxC xs)   
+ src/Synthesizer/Generic/Piece.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE NoImplicitPrelude #-}+{- |+These are pieces that can be assembled to a control curve.+This was formerly part of the @Control@ module+but because of the overlap with immediate control curve generators+I created a new module.+-}+module Synthesizer.Generic.Piece (+   T, run,+   step, linear, exponential,+   cosine, halfSine, cubic,+   FlatPosition(..),+   ) where++import qualified Synthesizer.Generic.Control as Ctrl+import qualified Synthesizer.Piecewise as Piecewise+import Synthesizer.Generic.Displacement (raise, )++import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.Generic.Signal as SigG+-- import qualified Synthesizer.State.Signal as Sig+import Synthesizer.State.Control (splitDurations, FlatPosition(..), )++import qualified Algebra.Transcendental        as Trans+import qualified Algebra.RealField             as RealField+import qualified Algebra.Field                 as Field+import qualified Algebra.Ring                  as Ring+import qualified Algebra.Additive              as Additive++import qualified Prelude as P+import PreludeBase+import NumericPrelude++++{-# INLINE run #-}+run :: (RealField.C a, CutG.Transform (sig a)) =>+   SigG.LazySize ->+   Piecewise.T a a (SigG.LazySize -> a -> sig a) ->+   sig a+run lazySize xs =+   SigG.concat $ zipWith+      (\(n, t) (Piecewise.PieceData c yi0 yi1 d) ->+           SigG.take n $ Piecewise.computePiece c yi0 yi1 d lazySize t)+      (splitDurations $ map Piecewise.pieceDur xs)+      xs+++type T sig a =+   Piecewise.Piece a a+      (SigG.LazySize -> a {- fractional start time -} -> sig a)+++{-# INLINE step #-}+step :: (SigG.Write sig a) => T sig a+step =+   Piecewise.pieceFromFunction $ \ y0 _y1 _d lazySize _t0 ->+      Ctrl.constant lazySize y0++{-# INLINE linear #-}+linear :: (Field.C a, SigG.Write sig a) => T sig a+linear =+   Piecewise.pieceFromFunction $ \ y0 y1 d lazySize t0 ->+      let s = (y1-y0)/d+      in  Ctrl.linear lazySize s (y0-t0*s)++{-# INLINE exponential #-}+exponential :: (Trans.C a, SigG.Write sig a) => a -> T sig a+exponential saturation =+   Piecewise.pieceFromFunction $ \ y0 y1 d lazySize t0 ->+      let y0' = y0-saturation+          y1' = y1-saturation+          yd  = y0'/y1'+      in  raise saturation+             (Ctrl.exponential lazySize (d / log yd) (y0' * yd**(t0/d)))++{-# INLINE cosine #-}+cosine :: (Trans.C a, SigG.Write sig a) => T sig a+cosine =+   Piecewise.pieceFromFunction $ \ y0 y1 d lazySize t0 ->+      SigG.map+         (\y -> ((1+y)*y0+(1-y)*y1)/2)+         (Ctrl.cosine lazySize t0 (t0+d))+++{- |+> Graphics.Gnuplot.Simple.plotList [] $ Sig.toList $ run $ 1 |# (10.9, halfSine FlatRight) #| 2+-}+{-# INLINE halfSine #-}+halfSine :: (Trans.C a, SigG.Write sig a) => FlatPosition -> T sig a+halfSine FlatLeft =+   Piecewise.pieceFromFunction $ \ y0 y1 d lazySize t0 ->+      SigG.map+         (\y -> y*y0 + (1-y)*y1)+         (Ctrl.cosine lazySize t0 (t0+2*d))+halfSine FlatRight =+   Piecewise.pieceFromFunction $ \ y0 y1 d lazySize t0 ->+      SigG.map+         (\y -> (1+y)*y0 - y*y1)+         (Ctrl.cosine lazySize (t0-d) (t0+d))+++{-# INLINE cubic #-}+cubic :: (Field.C a, SigG.Write sig a) => a -> a -> T sig a+cubic yd0 yd1 =+   Piecewise.pieceFromFunction $ \ y0 y1 d lazySize t0 ->+      Ctrl.cubicHermite lazySize (t0,(y0,yd0)) (t0+d,(y1,yd1))
src/Synthesizer/Generic/Signal.hs view
@@ -51,9 +51,9 @@ import Data.Tuple.HT (mapPair, mapFst, )  import Prelude-   (Bool, Int, Maybe(Just), maybe, snd,-    flip, uncurry, (.), ($), id,-    fmap, return, )+   (Bool, Int, Maybe(Just), maybe, snd, (<),+    flip, uncurry, const, (.), ($), id, (++),+    fmap, return, error, show, )   class Cut.Read (sig y) => Read sig y where@@ -395,6 +395,14 @@ tails =    SigS.unfoldR (fmap (\x -> (x, fmap snd (viewL x)))) . Just +{- |+Like 'tail', but for an empty signal it simply returns an empty signal.+-}+{-# INLINE laxTail #-}+laxTail :: (Transform sig y) => sig y -> sig y+laxTail xs =+   switchL xs (flip const) xs+ {-# INLINE mapAdjacent #-} mapAdjacent :: (Read sig a, Transform sig a) =>    (a -> a -> a) -> sig a -> sig a@@ -496,6 +504,20 @@    (+) = mix    negate = map Additive.negate -}++++{-+ToDo: make a method of Read class+-}+index :: (Transform sig a) => sig a -> Int -> a+index xs n =+   if n<0+     then error $ "Generic.index: negative index " ++ show n+     else switchL+             (error $ "Generic.index: index too large " ++ show n)+             const+             (Cut.drop n xs)   {-
src/Synthesizer/Generic/Tutorial.hs view
@@ -13,6 +13,7 @@ import qualified Synthesizer.Plain.Tutorial as Tutorial -- needed for Haddock  import qualified Sound.Sox.Play as Play+import qualified Sound.Sox.Write as Write import qualified Sound.Sox.Option.Format as SoxOpt import qualified Synthesizer.Basic.Binary as BinSmp import qualified Synthesizer.Storable.Signal as SigSt@@ -23,10 +24,12 @@ import Control.Arrow ((&&&), (^<<), (<<^), (<<<), )  import qualified Synthesizer.Generic.Oscillator as Osci+import qualified Synthesizer.Generic.Piece as Piece import qualified Synthesizer.Generic.Filter.NonRecursive as Filt import qualified Synthesizer.Plain.Filter.Recursive as FiltRec import qualified Synthesizer.Plain.Filter.Recursive.Universal as UniFilter import qualified Synthesizer.Basic.Wave as Wave+import Synthesizer.Piecewise ((#|-), (-|#), (#|), (|#), )  import qualified Synthesizer.State.Control as CtrlS import qualified Synthesizer.State.Oscillator as OsciS@@ -62,6 +65,37 @@ oscillator :: IO ExitCode oscillator =    play (Osci.static SigG.defaultLazySize Wave.sine zero (0.01::Double))+++{- |+A routine just for the case that we want to post-process a signal somewhere else.+-}+write :: FilePath -> SigSt.T Double -> IO ExitCode+write name =+   Write.simple SigSt.hPut SoxOpt.none name 44100 .+   SigSt.map BinSmp.int16FromDouble++{- |+The simple brass sound demonstrates+how to generate piecewise defined curves.+Some infix operators are used in order to make the pieces fit in height.+There are also operators for intended jumps.+-}+brass :: IO ExitCode+brass =+--   write "brass.aiff" $+   play $+   Filt.envelope+      (Piece.run SigG.defaultLazySize $+       0    |# ( 3000, Piece.cubic 0.002 0) #|-+       0.7 -|# (50000, Piece.step) #|-+       0.7 -|# (10000, Piece.exponential 0) #| (0.01::Double)) $+   SigG.fromState SigG.defaultLazySize $+   Filt.amplify 0.5 $+   SigG.mix+      (OsciS.static Wave.saw zero (0.00499::Double))+      (OsciS.static Wave.saw zero (0.00501::Double))+  {- | We rewrite the filter example 'Tutorial.filterSaw'
src/Synthesizer/Piecewise.hs view
@@ -3,7 +3,11 @@ -} module Synthesizer.Piecewise where -+{-+ToDo:+Make it a new data type with Monoid and Generic.Cut instances.+However there is no fast and generic way for splitting a piece.+-} type T t y sig = [PieceData t y sig]  {- |
src/Synthesizer/Plain/Control.hs view
@@ -326,6 +326,7 @@   +{-# DEPRECATED Control "use Synthesizer.State.Piece instead" #-} {- | The curve type of a piece of a piecewise defined control curve. -}
src/Synthesizer/Plain/Filter/NonRecursive.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE NoImplicitPrelude #-} {- |-Copyright   :  (c) Henning Thielemann 2006+Copyright   :  (c) Henning Thielemann 2006-2009 License     :  GPL  Maintainer  :  synthesizer@henning-thielemann.de@@ -22,6 +22,8 @@ import Algebra.Module(linearComb, (*>))  import Data.Function.HT (nest, )+import Data.Tuple.HT (mapPair, )+import Data.List.HT (sliceVertical, ) import Data.List (tails, )  -- import Control.Monad.Trans.State (StateT)@@ -204,7 +206,7 @@ and a list of sums of (2*k) of successive summands, compute a list of the sums of (2*k+1) or (2*k+2) summands. -Eample for 2*k+1+Example for 2*k+1  @  [0+1+2+3, 2+3+4+5, 4+5+6+7, ...] ->@@ -243,10 +245,123 @@    in  aux  -{--*Synthesizer.Plain.Filter.NonRecursive> movingAverageModulated 10 (replicate 10 (3::Double) ++ [1.1,2.2,2.6,0.7,0.1,0.1]) (repeat (1::Double))-[0.5,0.6666666666666666,0.8333333333333333,1.0,1.0,1.0,1.0,1.0,1.0,1.0,0.9999999999999999,1.0,0.9999999999999998,0.999999999999999,0.9999999999999942,0.9999999999999942]+{- |+Compute the sum of the values from index l to (r-1).+(I.e. somehow a right open interval.)+This can be used for implementation of a moving average filter.+However, its counterpart 'sumRangeFromPyramid'+is much faster for large windows. -}+sumRange :: (Additive.C v) => Sig.T v -> (Int,Int) -> v+sumRange =+   sumRangePrepare $ \ (l,r) ->+   sum . take (r-l) . drop l++pyramid :: (Additive.C v) => Sig.T v -> [Sig.T v]+pyramid = iterate sumsDownsample2++sumRangePrepare :: (Additive.C v) =>+   ((Int,Int) -> source -> v) ->+   (source -> (Int,Int) -> v)+sumRangePrepare f pyr (l,r) =+   case compare l r of+      LT -> f (l,r) pyr+      GT -> negate $ f (r,l) pyr+      EQ -> zero++{- |+This function should be much faster than 'sumRange'+but slower than the recursively implemented @movingAverage@.+However in contrast to @movingAverage@+it should not suffer from cancelation.+-}+sumRangeFromPyramid :: (Additive.C v) => [Sig.T v] -> (Int,Int) -> v+sumRangeFromPyramid =+   sumRangePrepare $ \(l0,r0) pyr0 ->+   sum $+   case pyr0 of+      [] -> error "empty pyramid"+      (ps0:pss) ->+         foldr+            (\psNext k ((l,r), ps) ->+               let (lh,ll) = - divMod (-l) 2+                   (rh,rl) =   divMod   r  2+                   ls = if ll==0 then [] else [ps!!l]+                   rs = if rl==0 then [] else [ps!!(r-1)]+               in  case r-l of+                     0 -> []+                     1 -> [ps!!l]+                     _ -> ls ++ rs ++ k ((lh,rh), psNext))+            (\((l,r), ps) -> take (r-l) $ drop l ps)+            pss ((l0,r0), ps0)++{- mapAccumL cannot work since the pyramid might be infinitely high+   sum $ takeWhileJust $ snd $+   mapAccumL () (l0,r0) $+   zip pyr0 $+   tail (Match.replicate pyr0 False ++ [True])+-}++sumRangeFromPyramidRec :: (Additive.C v) => [Sig.T v] -> (Int,Int) -> v+sumRangeFromPyramidRec =+   let recourse s (l,r) pyr =+          case pyr of+             (ps:[]) ->+                s + (sum $ take (r-l) $ drop l ps)+             (ps:pss) ->+                let (lh,ll) = - divMod (-l) 2+                    (rh,rl) =   divMod   r  2+                    ls = if ll==0 then zero else ps!!l+                    rs = if rl==0 then zero else ps!!(r-1)+                in  case r-l of+                      0 -> s+                      1 -> s+ps!!l+                      _ -> recourse (s + ls + rs) (lh,rh) pss+             [] -> error "empty pyramid"+   in  sumRangePrepare (recourse zero)++sumsPosModulated :: (Additive.C v) =>+   Sig.T (Int,Int) -> Sig.T v -> Sig.T v+sumsPosModulated ctrl xs =+   zipWith sumRange (tails xs) ctrl++{- |+Moving average, where window bounds must be always non-negative.++The laziness granularity is @2^height@.+-}+sumsPosModulatedPyramid :: (Additive.C v) =>+   Int -> Sig.T (Int,Int) -> Sig.T v -> Sig.T v+sumsPosModulatedPyramid height ctrl xs =+   let blockSize = 2 ^ fromIntegral height+       sizes =+          reverse $ take (1+height) $ iterate (2*) 1+       pyrStarts =+          iterate (zipWith drop sizes) $+          take (1+height) $ pyramid xs+       ctrlBlocks =+          map (zipWith (\d -> mapPair ((d+), (d+))) $ iterate (1+) 0) $+          sliceVertical blockSize ctrl+   in  concat $+       zipWith+          (\pyr -> map (sumRangeFromPyramid pyr))+          pyrStarts ctrlBlocks++{- |+The first argument is the amplification.+The main reason to introduce it,+was to have only a Module constraint instead of Field.+This way we can also filter stereo signals.+-}+movingAverageModulatedPyramid ::+   (Field.C a, Module.C a v) =>+   a -> Int -> Int -> Sig.T Int -> Sig.T v -> Sig.T v+movingAverageModulatedPyramid amp height maxC ctrl xs =+   zipWith (\c x -> (amp / fromIntegral (2*c+1)) *> x) ctrl $+   sumsPosModulatedPyramid height+      (map (\c -> (maxC - c, maxC + c)) ctrl)+      (delay maxC xs)+   {- * Filter operators from calculus -}
src/Synthesizer/Plain/Filter/Recursive/MovingAverage.hs view
@@ -133,6 +133,11 @@        negXs = sumDiffsModulated d0 (map (d0-) ds) delXs    in  Integration.run (posXs - negXs) +{-+*Synthesizer.Plain.Filter.NonRecursive> movingAverageModulated 10 (replicate 10 (3::Double) ++ [1.1,2.2,2.6,0.7,0.1,0.1]) (repeat (1::Double))+[0.5,0.6666666666666666,0.8333333333333333,1.0,1.0,1.0,1.0,1.0,1.0,1.0,0.9999999999999999,1.0,0.9999999999999998,0.999999999999999,0.9999999999999942,0.9999999999999942]+-}+ modulatedFrac :: (RealField.C a, Module.C a v) =>    Int -> Sig.T a -> Sig.T v -> Sig.T v modulatedFrac maxDInt ds xs =
src/Synthesizer/State/Control.hs view
@@ -29,6 +29,8 @@ -- import Number.Complex (cis,real) -- import qualified Number.Complex as Complex +import Data.Ix (Ix, )+ import qualified Prelude as P import PreludeBase import NumericPrelude@@ -243,8 +245,30 @@ cosinePiece =    Piecewise.pieceFromFunction $ \ y0 y1 d t0 ->       Sig.map-         (\y -> (1+y)*(y0/2)+(1-y)*(y1/2))+         (\y -> ((1+y)*y0+(1-y)*y1)/2)          (cosine t0 (t0+d))+++data FlatPosition =+   FlatLeft | FlatRight+      deriving (Show, Eq, Ord, Ix, Enum)++{- |+> Graphics.Gnuplot.Simple.plotList [] $ Sig.toList $ piecewise $ 1 |# (10.9, halfSinePiece FlatRight) #| 2+-}+{-# INLINE halfSinePiece #-}+halfSinePiece :: (Trans.C a) => FlatPosition -> Piece a+halfSinePiece FlatLeft =+   Piecewise.pieceFromFunction $ \ y0 y1 d t0 ->+      Sig.map+         (\y -> y*y0 + (1-y)*y1)+         (cosine t0 (t0+2*d))+halfSinePiece FlatRight =+   Piecewise.pieceFromFunction $ \ y0 y1 d t0 ->+      Sig.map+         (\y -> (1+y)*y0 - y*y1)+         (cosine (t0-d) (t0+d))+  {-# INLINE cubicPiece #-} cubicPiece :: (Field.C a) => a -> a -> Piece a
src/Synthesizer/State/Signal.hs view
@@ -32,6 +32,7 @@  import qualified Synthesizer.Storable.Signal as SigSt import qualified Data.StorableVector.Lazy.Pattern as SVL+import qualified Data.StorableVector as V import Foreign.Storable (Storable)  import qualified Data.List.HT as ListHT@@ -106,6 +107,13 @@ toStorableSignal size (Cons f a) =    SigSt.unfoldr size (runStateT f) a +{-# INLINE toStrictStorableSignal #-}+toStrictStorableSignal ::+   (Storable a) =>+   Int -> T a -> V.Vector a+toStrictStorableSignal size (Cons f a) =+   fst $ V.unfoldrN size (runStateT f) a+ -- needed in synthesizer-alsa {-# INLINE toStorableSignalVary #-} toStorableSignalVary ::@@ -582,15 +590,20 @@ --   map fromList . Sig.sliceVert n . toList    List.map (take n) . List.takeWhile (not . null) . List.iterate (drop n) +{-# DEPRECATED zapWith, zapWithAlt "use mapAdjacent" #-} {-# INLINE zapWith #-} zapWith :: (a -> a -> b) -> T a -> T b-zapWith f =-   switchL empty-      (crochetL (\y x -> Just (f x y, y)))+zapWith = mapAdjacent  zapWithAlt :: (a -> a -> b) -> T a -> T b zapWithAlt f xs =    zipWith f xs (switchL empty (curry snd) xs)++{-# INLINE mapAdjacent #-}+mapAdjacent :: (a -> a -> b) -> T a -> T b+mapAdjacent f =+   switchL empty+      (crochetL (\y x -> Just (f x y, y)))  {-# INLINE modifyStatic #-} modifyStatic :: Modifier.Simple s ctrl a b -> ctrl -> T a -> T b
src/Synthesizer/Storable/Cut.hs view
@@ -24,9 +24,6 @@ import NumericPrelude  -{- |-ChunkSize is only required for zero padding.--} {-# INLINE arrange #-} arrange :: (Storable v, Additive.C v) =>        Sig.ChunkSize@@ -36,7 +33,23 @@                 of the previous event. -}     -> Sig.T v             {-^ The mixed signal. -}-arrange size =+arrange =+   arrangeEquidist++{- |+Chunk sizes are adapted to the time differences.+Explicit ChunkSize parameter is only required for zero padding.+Since no ST monad is needed, this can be generalized to Generic.Signal.Transform class.+-}+arrangeAdaptive :: (Storable v, Additive.C v) =>+       Sig.ChunkSize+    -> EventList.T NonNeg.Int (Sig.T v)+            {-^ A list of pairs: (relative start time, signal part),+                The start time is relative to the start time+                of the previous event. -}+    -> Sig.T v+            {-^ The mixed signal. -}+arrangeAdaptive size =    uncurry Sig.append .    flip runState Sig.empty .    fmap (Sig.concat . EventList.getTimes) .@@ -87,6 +100,11 @@  {- | The result is a Lazy StorableVector with chunks of the given size.+The output is always infinite.+If the input is a finite list of finite length sounds,+then the output is padded with zeros.+Even if we try to terminate the output after the last sound,+we would not finish immediately but only at chunk boundaries. -} {-# INLINE arrangeEquidist #-} arrangeEquidist :: (Storable v, Additive.C v) =>@@ -104,7 +122,7 @@               xs =                  AbsEventList.toPairList $                  EventList.toAbsoluteEventList 0 $-                 EventListTM.switchTimeR (const) now+                 EventListTM.switchTimeR const now               (chunk,newAcc) =                  runST                     (do v <- SVST.new sz zero@@ -122,7 +140,24 @@  addToBuffer :: (Storable a, Additive.C a) =>    SVST.Vector s a -> Int -> Sig.T a -> ST s (Sig.T a)-addToBuffer v start =+addToBuffer v start xs =+   let n = SVST.length v+       (now,future) = Sig.splitAt (n Additive.- start) xs+   in  Sig.foldr+          (\x continue i ->+             SVST.modify v i (x Additive.+) >>+             continue (succ i))+          (const $ return ()) now start+        >> return future+++{-+Using @Sig.switchL@ in an inner loop+is slower than using @Sig.foldr@.+-}+addToBufferSwitchL :: (Storable a, Additive.C a) =>+   SVST.Vector s a -> Int -> Sig.T a -> ST s (Sig.T a)+addToBufferSwitchL v start =    let n = SVST.length v        {-# INLINE go #-}        go i =
+ src/Synthesizer/Storable/Filter/NonRecursive.hs view
@@ -0,0 +1,202 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE FlexibleContexts #-}+{- |+Copyright   :  (c) Henning Thielemann 2008-2009+License     :  GPL++Maintainer  :  synthesizer@henning-thielemann.de+Stability   :  provisional+Portability :  requires multi-parameter type classes+-}+module Synthesizer.Storable.Filter.NonRecursive where++import qualified Synthesizer.Storable.Signal as SigSt+import qualified Data.StorableVector as V+import qualified Data.StorableVector.Lazy as VL+import qualified Data.StorableVector.Lazy.Pattern as VP++import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.State.Signal as SigS+import qualified Synthesizer.Plain.Filter.NonRecursive as Filt+import qualified Synthesizer.Generic.Filter.NonRecursive as FiltG++import qualified Algebra.Module         as Module+import qualified Algebra.Field          as Field+import qualified Algebra.Ring           as Ring+import qualified Algebra.Additive       as Additive++import Foreign.Storable (Storable, )+import Foreign.Storable.Tuple ()++import Algebra.Module( {- linearComb, -} (*>), )++import Control.Monad (mplus, )++import qualified Data.List as List+import Data.Tuple.HT (mapFst, mapSnd, mapPair, swap, )++import qualified Numeric.NonNegative.Chunky as NonNegChunky++import PreludeBase+import NumericPrelude as NP+import qualified Prelude as P+++{- |+The Maybe type carries an unpaired value from one block to the next one.+-}+sumsDownsample2Strict ::+   (Additive.C v, Storable v) =>+   Maybe v -> V.Vector v -> (Maybe v, V.Vector v)+sumsDownsample2Strict carry ys =+   mapFst (\v -> fmap fst $ V.viewL . snd =<< v) $ swap $+   V.unfoldrN (div (V.length ys + maybe 0 (const 1) carry) 2) (\(carry0,xs0) ->+      do (x0,xs1) <- mplus (fmap (\c -> (c, xs0)) carry0) (V.viewL xs0)+         (x1,xs2) <- V.viewL xs1+         return (x0+x1, (Nothing, xs2)))+      (carry, ys)++sumsDownsample2 ::+   (Additive.C v, Storable v) =>+   SigSt.T v -> SigSt.T v+sumsDownsample2 =+   SigSt.fromChunks .+   filter (not . V.null) .+   (\(carry, chunks) ->+      chunks ++ maybe [] (\cr -> [V.singleton cr]) carry) .+   List.mapAccumL sumsDownsample2Strict Nothing .+   SigSt.chunks++sumsDownsample2Alt ::+   (Additive.C v, Storable v) =>+   SigSt.T v -> SigSt.T v+sumsDownsample2Alt ys =+   fst .+   VP.unfoldrN (halfLazySize $ VP.length ys) (\xs ->+      flip fmap (SigS.viewL xs) $ \xxs0@(x0,xs0) ->+         SigS.switchL xxs0 {- xs0 is empty -}+            (\ x1 xs1 -> (x0+x1, xs1))+            xs0)+    . SigS.fromStorableSignal $ ys++halfLazySize :: NonNegChunky.T VP.ChunkSize -> NonNegChunky.T VP.ChunkSize+halfLazySize =+   NonNegChunky.fromChunks .+   filter (VL.ChunkSize zero /=) .+   (\(c,ls) -> ls ++ [VL.ChunkSize c]) .+   List.mapAccumL (\c (VL.ChunkSize l) ->+      mapSnd VL.ChunkSize $ swap $ divMod (c+l) 2) zero .+   NonNegChunky.toChunks++{- |+offset must be zero or one.+-}+downsample2Strict ::+   (Storable v) =>+   Int -> V.Vector v -> V.Vector v+downsample2Strict offset ys =+   fst $+   V.unfoldrN (- div (offset - V.length ys) 2)+      (fmap (mapSnd laxTailStrict) . V.viewL) $+   if offset == 0+     then ys+     else laxTailStrict ys++laxTailStrict ::+   (Storable v) =>+   V.Vector v -> V.Vector v+laxTailStrict ys =+   V.switchL ys (flip const) ys++downsample2 ::+   (Storable v) =>+   SigSt.T v -> SigSt.T v+downsample2 =+   SigSt.fromChunks .+   filter (not . V.null) .+   snd .+   List.mapAccumL+      (\k c ->+         (mod (k + V.length c) 2, downsample2Strict k c)) zero .+   SigSt.chunks+++pyramid ::+   (Additive.C v, Storable v) =>+   Int -> SigSt.T v -> [SigSt.T v]+pyramid height =+   take (1+height) . iterate sumsDownsample2++{-+This function uses the efficient Storable.index function.+If @Generic.index@ becomes as fast as @Storable.index@+then we can replace this function by its generic counterpart.+-}+sumRangeFromPyramid ::+   (Additive.C v, Storable v) =>+   [SigSt.T v] -> (Int,Int) -> v+sumRangeFromPyramid =+   Filt.sumRangePrepare $ \(l0,r0) pyr0 ->+   case pyr0 of+      [] -> error "empty pyramid"+      (ps0:pss) ->+         foldr+            (\psNext k (l,r) ps s ->+               case r-l of+                  0 -> s+                  1 -> s + VL.index ps l+                  _ ->+                     let (lh,ll) = NP.negate $ divMod (NP.negate l) 2+                         (rh,rl) = divMod r 2+                         {-# INLINE inc #-}+                         inc b x = if b==0 then id else (x+)+                     in  k (lh,rh) psNext $+                         inc ll (VL.index ps l) $+                         inc rl (VL.index ps (r-1)) $+                         s)+            (\(l,r) ps s ->+               s + (SigG.sum $ SigSt.take (r-l) $ SigSt.drop l ps))+            pss (l0,r0) ps0 zero++{- |+Moving average, where window bounds must be always non-negative.++The laziness granularity of the input signal is maintained.+-}+sumsPosModulatedPyramid ::+   (Additive.C v, Storable (Int,Int), Storable v) =>+   Int -> SigSt.T (Int,Int) -> SigSt.T v -> SigSt.T v+sumsPosModulatedPyramid height ctrl xs =+   let pyr0 = pyramid height xs+       sizes =+          reverse $ take (1+height) $ iterate (2*) 1+       blockSize = head sizes+       pyrStarts =+          iterate (zipWith SigSt.drop sizes) pyr0+       ctrlBlocks =+          SigS.toList $+          SigG.sliceVertical blockSize ctrl+   in  SigSt.fromChunks $+       zipWith+          (\pyr ->+              SigS.toStrictStorableSignal blockSize .+              SigS.map (sumRangeFromPyramid pyr) .+              SigS.zipWith (\d -> mapPair ((d+), (d+))) (SigS.iterate (1+) 0) .+              SigS.fromStorableSignal)+          pyrStarts ctrlBlocks++{- |+The first argument is the amplification.+The main reason to introduce it,+was to have only a Module constraint instead of Field.+This way we can also filter stereo signals.+-}+movingAverageModulatedPyramid ::+   (Field.C a, Module.C a v,+    Storable Int, Storable v) =>+   a -> Int -> Int -> SigSt.T Int -> SigSt.T v -> SigSt.T v+movingAverageModulatedPyramid amp height maxC ctrl xs =+   SigSt.zipWith (\c x -> (amp / fromIntegral (2*c+1)) *> x) ctrl $+   sumsPosModulatedPyramid height+      (SigSt.map (\c -> (maxC - c, maxC + c)) ctrl)+      (FiltG.delay maxC xs)
src/Synthesizer/Storable/Signal.hs view
@@ -34,6 +34,7 @@       splitAtPad,       Vector.null,       Vector.fromChunks,+      Vector.foldr,       -- for Storable.Filter.Comb       delay,       delayLoop,@@ -54,6 +55,10 @@       zipWithAppend,       -- for Storable.ALSA.MIDI       Vector.switchR,+      -- for Test.Filter+      toList,+      -- for Storable.Filter.NonRecursive+      Vector.chunks,        -- just for fun       fromFusionList,@@ -290,6 +295,10 @@ {-# INLINE fromList #-} fromList :: (Storable a) => ChunkSize -> [a] -> T a fromList = Vector.pack++{-# INLINE toList #-}+toList :: (Storable a) => T a -> [a]+toList = Vector.unpack   {-
src/Test/Sound/Synthesizer/Plain/Filter.hs view
@@ -3,17 +3,33 @@ import qualified Synthesizer.Plain.Filter.Recursive.MovingAverage as MA import qualified Synthesizer.Plain.Filter.NonRecursive as FiltNR import qualified Synthesizer.Plain.Signal as Sig+import qualified Synthesizer.Generic.Filter.NonRecursive as FiltNRG+import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Storable.Filter.NonRecursive as FiltNRSt+import qualified Synthesizer.Storable.Signal as SigSt+import qualified Synthesizer.Frame.Stereo as Stereo +import qualified Data.StorableVector.Lazy.Pattern as VP++import Foreign.Storable.Tuple ()+ import Test.QuickCheck (test, {- Property, (==>) -})--- import Test.Utility (equalList, approxEqualListAbs, approxEqualListRel, )+import Test.Utility (equalList, {- approxEqualListAbs, approxEqualListRel, -} )  -- import qualified Algebra.Module                as Module -- import qualified Algebra.RealField             as RealField -- import qualified Algebra.Ring                  as Ring -- import qualified Algebra.Additive              as Additive +import qualified Number.GaloisField2p32m5 as GF import qualified Number.NonNegative       as NonNeg +import qualified Numeric.NonNegative.Chunky as Chunky++import Data.Tuple.HT (mapPair, )++-- import Debug.Trace (trace, )+ import NumericPrelude import PreludeBase import Prelude ()@@ -31,8 +47,105 @@        and $ zipWith3 (\x y z -> x==y && y==z) naive rec pyramid        -- equalList $ naive : pyramid : rec : [] +sumRange :: NonNeg.Int -> (NonNeg.Int, NonNeg.Int) -> Sig.T Int -> Bool+sumRange nheight (nl,nr) xs =+   let wrap n = mod (NonNeg.toNumber n) (length xs + 1)+       height = 1 + NonNeg.toNumber nheight+       rng = (wrap nl, wrap nr)+   in  equalList $+       FiltNR.sumRange xs rng :+       FiltNR.sumRangeFromPyramid (take height (FiltNR.pyramid xs)) rng :+       FiltNR.sumRangeFromPyramidRec (take height (FiltNR.pyramid xs)) rng :+       FiltNRSt.sumRangeFromPyramid+          (FiltNRSt.pyramid height+             (SigSt.fromList SigSt.defaultChunkSize xs)) rng :+       [] +sumsPosModulated ::+   NonNeg.Int -> Sig.T (NonNeg.Int,NonNeg.Int) -> (Int, Sig.T Int) -> Bool+sumsPosModulated nheight nctrl xsc =+   let ctrl = map (mapPair (NonNeg.toNumber, NonNeg.toNumber)) nctrl+       xs = cycle $ uncurry (:) xsc+       height = min 10 $ NonNeg.toNumber nheight+   in  -- trace (show (height, ctrl, xsc)) $+       equalList $+       FiltNR.sumsPosModulated ctrl xs :+       FiltNR.sumsPosModulatedPyramid height ctrl xs :+       FiltNRG.sumsPosModulatedPyramid height ctrl xs :+       SigSt.toList+          (FiltNRG.sumsPosModulatedPyramid+             height+             (SigSt.fromList SigSt.defaultChunkSize ctrl)+             (SigSt.fromList SigSt.defaultChunkSize xs)) :+       SigSt.toList+          (FiltNRSt.sumsPosModulatedPyramid+             height+             (SigSt.fromList SigSt.defaultChunkSize ctrl)+             (SigSt.fromList SigSt.defaultChunkSize xs)) :+       []++downSample2 ::+   [Int] -> (Int, Sig.T Int) -> Bool+downSample2 lazySize xsc =+   let len = Chunky.fromChunks $ map (VP.chunkSize . succ . abs) lazySize+       xs = VP.pack len $ cycle $ uncurry (:) xsc+   in  equalList $+       FiltNRG.downsample2 SigG.defaultLazySize xs :+       FiltNRSt.downsample2 xs :+       []++sumsDownSample2 ::+   [Int] -> (Int, Sig.T Int) -> Bool+sumsDownSample2 lazySize xsc =+   let len = Chunky.fromChunks $ map (VP.chunkSize . succ . abs) lazySize+       xs = VP.pack len $ cycle $ uncurry (:) xsc+   in  equalList $+       FiltNRG.sumsDownsample2 SigG.defaultLazySize xs :+       FiltNRSt.sumsDownsample2 xs :+       FiltNRSt.sumsDownsample2Alt xs :+       []++{-+sumsDownSample2 ::+   [VP.ChunkSize] -> (Int, Sig.T Int) -> Bool+sumsDownSample2 lazySize xsc =+   let len = Chunky.fromChunks $ filter (0/=) lazySize+       xs = VP.pack len $ cycle $ uncurry (:) xsc+   in  equalList $+       FiltNRG.sumsDownsample2 SigG.defaultLazySize xs :+       FiltNRSt.sumsDownsample2 xs :+       FiltNRSt.sumsDownsample2Alt xs :+       []+-}++movingAverageModulatedPyramid ::+   NonNeg.Int -> Sig.T NonNeg.Int ->+   (Stereo.T GF.T, Sig.T (Stereo.T GF.T)) -> Bool+movingAverageModulatedPyramid nheight nctrl xsc =+   let ctrl = map NonNeg.toNumber nctrl+       xs = uncurry (:) xsc+       pack ys = SigSt.fromList SigSt.defaultChunkSize ys+       maxC = maximum ctrl+       height = min 10 $ NonNeg.toNumber nheight+       onegf :: GF.T+       onegf = one+   in  -- trace (show (height, ctrl, xsc)) $+       equalList $+       pack (FiltNR.movingAverageModulatedPyramid onegf+          height maxC ctrl (cycle xs)) :+       FiltNRG.movingAverageModulatedPyramid onegf+          height maxC (pack ctrl) (SigG.cycle $ pack xs) :+       FiltNRSt.movingAverageModulatedPyramid onegf+          height maxC (pack ctrl) (SigG.cycle $ pack xs) :+       []++ tests :: [(String, IO ())] tests =    ("sums", test sums) :+   ("sumRange", test sumRange) :+   ("sumsPosModulated", test sumsPosModulated) :+   ("downSample2", test downSample2) :+   ("sumsDownSample2", test sumsDownSample2) :+   ("movingAverageModulatedPyramid", test movingAverageModulatedPyramid) :    []
synthesizer-core.cabal view
@@ -1,5 +1,5 @@ Name:           synthesizer-core-Version:        0.2+Version:        0.2.1 License:        GPL License-File:   LICENSE Author:         Henning Thielemann <haskell@henning-thielemann.de>@@ -51,7 +51,7 @@   Source-Repository this-  Tag:         0.2+  Tag:         0.2.1   Type:        darcs   Location:    http://code.haskell.org/synthesizer/core/ @@ -64,15 +64,16 @@     transformers >=0.0.1 && <0.2,     event-list >=0.0.8 && <0.1,     non-negative >=0.0.5 && <0.1,-    numeric-prelude >=0.1.1 && <0.2,+    numeric-prelude >=0.1.2 && <0.2,     numeric-quest >= 0.1 && <0.2,     utility-ht >=0.0.5 && <0.1,     sox >=0.0 && <0.1,     filepath >=1.1 && <1.2,     bytestring >= 0.9 && <0.10,     binary >=0.1 && <1,-    storablevector >=0.2.3 && <0.3,+    storablevector >=0.2.4 && <0.3,     storable-record >=0.0.1 && <0.1,+    storable-tuple >=0.0.1 && <0.1,     QuickCheck >=1 && <2    If flag(splitBase)@@ -163,6 +164,7 @@     Synthesizer.Storable.Cut     Synthesizer.Storable.Oscillator     Synthesizer.Storable.Signal+    Synthesizer.Storable.Filter.NonRecursive     Synthesizer.State.Analysis     Synthesizer.State.Control     Synthesizer.State.Cut@@ -196,6 +198,7 @@     Synthesizer.Generic.Interpolation     Synthesizer.Generic.Noise     Synthesizer.Generic.Oscillator+    Synthesizer.Generic.Piece     Synthesizer.Generic.Signal     Synthesizer.Generic.Signal2     Synthesizer.Generic.Wave