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 +4/−4
- src/Synthesizer/Causal/ToneModulation.hs +1/−1
- src/Synthesizer/Filter/Basic.hs +1/−1
- src/Synthesizer/Filter/Composition.hs +1/−1
- src/Synthesizer/Frame/Stereo.hs +41/−4
- src/Synthesizer/FusionList/Control.hs +2/−9
- src/Synthesizer/Generic/Control.hs +1/−0
- src/Synthesizer/Generic/Filter/NonRecursive.hs +113/−10
- src/Synthesizer/Generic/Piece.hs +107/−0
- src/Synthesizer/Generic/Signal.hs +25/−3
- src/Synthesizer/Generic/Tutorial.hs +34/−0
- src/Synthesizer/Piecewise.hs +5/−1
- src/Synthesizer/Plain/Control.hs +1/−0
- src/Synthesizer/Plain/Filter/NonRecursive.hs +120/−5
- src/Synthesizer/Plain/Filter/Recursive/MovingAverage.hs +5/−0
- src/Synthesizer/State/Control.hs +25/−1
- src/Synthesizer/State/Signal.hs +16/−3
- src/Synthesizer/Storable/Cut.hs +41/−6
- src/Synthesizer/Storable/Filter/NonRecursive.hs +202/−0
- src/Synthesizer/Storable/Signal.hs +9/−0
- src/Test/Sound/Synthesizer/Plain/Filter.hs +114/−1
- synthesizer-core.cabal +7/−4
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