synthesizer-core 0.4.0.4 → 0.4.1
raw patch · 97 files changed
+3964/−444 lines, 97 filesdep +explicit-exceptiondep +timeitdep ~basedep ~containersdep ~numeric-preludenew-component:exe:fouriertest
Dependencies added: explicit-exception, timeit
Dependency ranges changed: base, containers, numeric-prelude, storablevector
Files
- speedtest/Fourier.hs +94/−0
- src/Synthesizer/Basic/ComplexModule.hs +2/−3
- src/Synthesizer/Basic/Distortion.hs +1/−2
- src/Synthesizer/Basic/DistortionControlled.hs +1/−3
- src/Synthesizer/Basic/NumberTheory.hs +896/−0
- src/Synthesizer/Basic/ToneModulation.hs +0/−5
- src/Synthesizer/Causal/Analysis.hs +34/−0
- src/Synthesizer/Causal/Displacement.hs +0/−1
- src/Synthesizer/Causal/Interpolation.hs +0/−2
- src/Synthesizer/Causal/Oscillator.hs +1/−4
- src/Synthesizer/Causal/Oscillator/Core.hs +0/−3
- src/Synthesizer/Causal/Spatial.hs +24/−0
- src/Synthesizer/ChunkySize/Cut.hs +1/−22
- src/Synthesizer/ChunkySize/Signal.hs +1/−5
- src/Synthesizer/Generic/Analysis.hs +7/−25
- src/Synthesizer/Generic/Control.hs +0/−6
- src/Synthesizer/Generic/Cut.hs +52/−29
- src/Synthesizer/Generic/Cyclic.hs +192/−0
- src/Synthesizer/Generic/Filter/NonRecursive.hs +339/−16
- src/Synthesizer/Generic/Filter/Recursive/Comb.hs +0/−2
- src/Synthesizer/Generic/Fourier.hs +997/−0
- src/Synthesizer/Generic/Interpolation.hs +0/−3
- src/Synthesizer/Generic/LengthSignal.hs +62/−0
- src/Synthesizer/Generic/Loop.hs +1/−3
- src/Synthesizer/Generic/Noise.hs +0/−2
- src/Synthesizer/Generic/Oscillator.hs +0/−14
- src/Synthesizer/Generic/Permutation.hs +151/−0
- src/Synthesizer/Generic/Piece.hs +0/−3
- src/Synthesizer/Generic/Signal.hs +127/−38
- src/Synthesizer/Generic/Signal2.hs +13/−2
- src/Synthesizer/Interpolation/Class.hs +0/−1
- src/Synthesizer/Interpolation/Custom.hs +0/−2
- src/Synthesizer/Interpolation/Module.hs +0/−5
- src/Synthesizer/Plain/Analysis.hs +27/−9
- src/Synthesizer/Plain/Builder.hs +1/−2
- src/Synthesizer/Plain/Control.hs +1/−5
- src/Synthesizer/Plain/Effect.hs +5/−3
- src/Synthesizer/Plain/Effect/Fly.hs +10/−7
- src/Synthesizer/Plain/Effect/Glass.hs +3/−6
- src/Synthesizer/Plain/File.hs +38/−14
- src/Synthesizer/Plain/Filter/Delay.hs +0/−2
- src/Synthesizer/Plain/Filter/Delay/Block.hs +0/−1
- src/Synthesizer/Plain/Filter/Delay/List.hs +0/−1
- src/Synthesizer/Plain/Filter/Delay/ST.hs +0/−1
- src/Synthesizer/Plain/Filter/LinearPredictive.hs +0/−2
- src/Synthesizer/Plain/Filter/NonRecursive.hs +1/−1
- src/Synthesizer/Plain/Filter/Recursive.hs +0/−4
- src/Synthesizer/Plain/Filter/Recursive/Allpass.hs +0/−3
- src/Synthesizer/Plain/Filter/Recursive/AllpassPoly.hs +0/−4
- src/Synthesizer/Plain/Filter/Recursive/Butterworth.hs +0/−3
- src/Synthesizer/Plain/Filter/Recursive/Chebyshev.hs +8/−8
- src/Synthesizer/Plain/Filter/Recursive/Comb.hs +0/−4
- src/Synthesizer/Plain/Filter/Recursive/FirstOrder.hs +13/−7
- src/Synthesizer/Plain/Filter/Recursive/FirstOrderComplex.hs +0/−5
- src/Synthesizer/Plain/Filter/Recursive/Hilbert.hs +0/−3
- src/Synthesizer/Plain/Filter/Recursive/Moog.hs +0/−4
- src/Synthesizer/Plain/Filter/Recursive/SecondOrder.hs +0/−4
- src/Synthesizer/Plain/Filter/Recursive/SecondOrderCascade.hs +0/−7
- src/Synthesizer/Plain/Filter/Recursive/Universal.hs +0/−1
- src/Synthesizer/Plain/IO.hs +0/−2
- src/Synthesizer/Plain/Interpolation.hs +0/−1
- src/Synthesizer/Plain/Miscellaneous.hs +15/−14
- src/Synthesizer/Plain/Noise.hs +0/−1
- src/Synthesizer/Plain/Oscillator.hs +0/−13
- src/Synthesizer/Plain/Signal.hs +6/−4
- src/Synthesizer/Plain/ToneModulation.hs +0/−3
- src/Synthesizer/Plain/Wave.hs +0/−4
- src/Synthesizer/State/Analysis.hs +4/−10
- src/Synthesizer/State/Control.hs +0/−6
- src/Synthesizer/State/Cut.hs +1/−1
- src/Synthesizer/State/Displacement.hs +0/−3
- src/Synthesizer/State/Filter/NonRecursive.hs +0/−2
- src/Synthesizer/State/Filter/Recursive/Comb.hs +0/−4
- src/Synthesizer/State/Interpolation.hs +0/−5
- src/Synthesizer/State/Noise.hs +0/−1
- src/Synthesizer/State/NoiseCustom.hs +0/−1
- src/Synthesizer/State/Signal.hs +59/−8
- src/Synthesizer/Storable/Cut.hs +0/−3
- src/Synthesizer/Storable/Filter/NonRecursive.hs +0/−3
- src/Synthesizer/Storable/Oscillator.hs +0/−4
- src/Test/Main.hs +14/−0
- src/Test/Sound/Synthesizer/Basic/NumberTheory.hs +119/−0
- src/Test/Sound/Synthesizer/Basic/ToneModulation.hs +0/−5
- src/Test/Sound/Synthesizer/Causal/Analysis.hs +32/−0
- src/Test/Sound/Synthesizer/Generic/Cut.hs +104/−0
- src/Test/Sound/Synthesizer/Generic/Filter.hs +64/−0
- src/Test/Sound/Synthesizer/Generic/Fourier.hs +152/−0
- src/Test/Sound/Synthesizer/Generic/FourierInteger.hs +178/−0
- src/Test/Sound/Synthesizer/Generic/Permutation.hs +45/−0
- src/Test/Sound/Synthesizer/Generic/ToneModulation.hs +0/−5
- src/Test/Sound/Synthesizer/Plain/Analysis.hs +0/−2
- src/Test/Sound/Synthesizer/Plain/Oscillator.hs +0/−8
- src/Test/Sound/Synthesizer/Plain/ToneModulation.hs +1/−4
- src/Test/Sound/Synthesizer/Plain/Wave.hs +0/−4
- src/Test/Sound/Synthesizer/Storable/Cut.hs +0/−3
- src/Test/Utility.hs +23/−4
- synthesizer-core.cabal +44/−4
+ speedtest/Fourier.hs view
@@ -0,0 +1,94 @@+module Main where++import qualified Synthesizer.Storable.Signal as SigSt+import qualified Synthesizer.Generic.Fourier as Fourier+import qualified Synthesizer.Generic.Noise as NoiseG+import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.State.Noise as NoiseS+import qualified Synthesizer.State.Signal as SigS++import qualified Data.StorableVector as SV++import qualified Algebra.Ring as Ring+import qualified Number.Complex as NPComplex++import System.TimeIt (timeIt, )++import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()++++test0 :: IO ()+test0 =+ SigSt.writeFile "fouriertest.f64" $+ SigG.take 65536 $+ (NoiseG.white SigG.defaultLazySize :: SigSt.T Double)++test1 :: IO ()+test1 =+ SigSt.writeFile "fouriertest.f64" $+ SigG.fromState SigG.defaultLazySize $+ SigS.take 65536 $+ SigS.map (NPComplex.+: 0) $+ (NoiseS.white :: SigS.T Double)++test2 :: Int -> IO ()+test2 n =+ writeFile "fouriertest.cache" $+ show $ Fourier.cacheBackward $+ (\sig ->+ SigG.fromState SigG.defaultLazySize sig ::+ SigSt.T (NPComplex.T Double)) $+ SigS.take n $+ SigS.map (NPComplex.+: 0) $+ NoiseS.white++test3 :: Int -> IO ()+test3 n =+ let sig :: SigSt.T (NPComplex.T Double)+ sig =+ SigG.fromState SigG.defaultLazySize $+ SigS.take n $+ SigS.map (NPComplex.+: 0) $+ NoiseS.white+ cache =+ Fourier.cacheBackward sig+ in do timeIt $ writeFile "fouriertest.cache" $ show cache+ timeIt $ SigSt.writeFile "fouriertest.f64" $+ Fourier.transformWithCache cache sig++test4 :: Int -> IO ()+test4 n =+ let sig :: SV.Vector (NPComplex.T Double)+ sig =+ SigS.toStrictStorableSignal n $+ SigS.take n $+ SigS.map (NPComplex.+: 0) $+ NoiseS.white+ cache =+ Fourier.cacheBackward sig+ in do -- timeIt $ writeFile "fouriertest.cache" $ show cache+ timeIt $ SV.writeFile "fouriertest.f64" $+ Fourier.transformWithCache cache sig+++main :: IO ()+main =+-- timeIt $ test2 (4096*3+1)+-- test4 (4096*3+1)+ sequence_ $+ timeIt test0 : timeIt test1 :+ map test4+ (16384 : (4096*3) : (4096*3+1) : 11025 :+ (3^9) : (5^6) : (7^5) :+ (6^6) : (3*5*7*11*13) :+ [])+{-+ (65536 : 65537 : 44100 :+ (3^10) : (5^7) : (7^5) :+ (6^6) : (2*3*5*7*11*13) :+ [])+-}
src/Synthesizer/Basic/ComplexModule.hs view
@@ -6,11 +6,10 @@ import qualified Number.Complex as Complex import qualified Algebra.Module as Module import Number.Complex ((+:), )-import Algebra.Module ((*>), ) -import qualified Prelude as P--- import NumericPrelude.Base import NumericPrelude.Numeric+-- import NumericPrelude.Base+import Prelude () {-# INLINE scale #-}
src/Synthesizer/Basic/Distortion.hs view
@@ -16,9 +16,8 @@ import qualified Algebra.Transcendental as Trans import qualified Algebra.RealField as RealField import qualified Algebra.Field as Field-import qualified Algebra.RealRing as RealRing+import qualified Algebra.RealRing as RealRing import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import Data.Ord.HT (limit, )
src/Synthesizer/Basic/DistortionControlled.hs view
@@ -10,9 +10,7 @@ import qualified Algebra.Transcendental as Trans import qualified Algebra.RealField as RealField import qualified Algebra.Field as Field-import qualified Algebra.RealRing as RealRing-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive+import qualified Algebra.RealRing as RealRing import Data.Ord.HT (limit, )
+ src/Synthesizer/Basic/NumberTheory.hs view
@@ -0,0 +1,896 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-+Some of these functions might be moved to NumericPrelude.++Wikipedia: (primitive) roots of unity modulo n+ (primitive) roots must be units and all units are (primitive) roots+ maximum possible order for primitive roots - Carmichael+ all possible orders: divisor of Carmichael (proof? statement already in Carmichael-function-article)+ sum of primitive roots that vanishes+ order of primitive root is a divisor of each possible exponent+ proof with GCD and diophantine in exponent+ check for primitive root: fast exponentiation,+ primitivity: check exponents that are prime divisors+ how to find a primitive root: just try+ sum of powers of a primitive root is zero+ number of primitive roots of given order+ g(n,k) > 0 if k|lambda(n)+ g(n,k) = 0 else+ g(n,1) = 1+ g(4,2) = 1+ g(2^n,2) = 3 for n>=3 ((-1) is always a square root of 1)+ g(2^n,2^k) = 2^k for k>=2 && k<n-1+ g(n,2) = 1 for n>=3 and n in OEIS:A033948+ sum(g(n,k), k\in\N) = phi(n)+ There are only a few patterns that occur as rows of g,+ but a row of g (i.e. g(n)) does functionally depend on+ either lambda(n) nor phi(n)+ lambda(14) = 6 nozeros(g(14)) = [1,1,2,2] (f ~ [1,2,3,6])+ lambda(21) = 6 nozeros(g(21)) = [1,3,2,6] (f ~ [1,4,3,12])+ phi(13) = 12 nozeros(g(13)) = [1,1,2,2,2,4] (f ~ [1,2,3,4,6,12])+ phi(21) = 12 nozeros(g(21)) = [1,3,2,6] (f ~ [1,4,3,12])+ However length(nozeros(f(n))) = numberofdivisors(lambda(n))+ numberofdivisors=A000005+ number of roots of given order+ easier to compute+ k|m => f(n,k) | f(n,m)+ g(n,k) = f(n,k) - sum(f(n,d), d|k and k/d prime) + ...+ inclusion-exclusion-principle+ better to write the other round:+ f(n,k) = sum(g(n,d), d|k) - this is Dirichlet convolution+ RUNM says f(n,k) is multiplicative+ list it in multiplicative function+ f(n,1) = 1 for n>=2+ f(n,lambda(n)) = phi(n)+ f(n,a·b) = f(n,a)·f(n,b) if a and b are coprime (conjecture)+ f(n,lcm(a,b)) = lcm(f(n,a),f(n,b)) (conjecture)+ If this conjecture is true, then we only need to know f(n,p^i).+ The following conjecture is wrong:+ for prime p it is f(n,p^i) = gcd(lambda(n),p^i)+ counterexamples+ f(8,2) = 4, lambda(8)=2+ f(63,3) = 9, lambda(63)=6+ f(275,5) = 25, lambda(275)=20+ f(1247,7) = 49, lambda(1247)=84+ It seems to be:+ for prime p it is f(n,p^i) = p^j for some j+ How to find a modulus where there is a primitive root of order o?+ just try numbers from the sequence o+1, 2*o+1, 3*o+1+ Because of [[Dirichlet's theorem on arithmetic progressions]]+ you will somewhen find a prime p,+ and its Carmichael value is p-1, which is a multiple of o.+ In this ring even 'o' is a unit.+ How to find a modulus where there are primitive roots of orders o1,..,ok?+ Just search for a modulus with roots of order lcm(o1,...,ok).+ The smallest such modulus should also be the smallest one+ that has primitive roots of orders o1,..,ok?+ Proof: If a ring has primitive roots of orders o1,..,ok+ then all orders divide the carmichael value of that ring,+ thus lcm(o1,...,ok) divides the carmichael value of that ring,+ thus there is a primitive root of order lcm(o1,...,ok).+-}+module Synthesizer.Basic.NumberTheory where++import qualified Synthesizer.State.Signal as SigS++import qualified Data.Set as Set+import qualified Data.Map as Map++import qualified Algebra.Ring as Ring+import qualified Algebra.Units as Units+import qualified Algebra.PrincipalIdealDomain as PID+import qualified Algebra.IntegralDomain as Integral+import qualified Algebra.ZeroTestable as ZeroTestable++import qualified Number.ResidueClass.Check as RC+import Number.ResidueClass.Check ((/:), )++import qualified Number.FixedPoint as FP+import Data.Bits (Bits, (.&.), (.|.), shiftR, )++import qualified Data.List.HT as ListHT+import Data.List (unfoldr, mapAccumL, genericDrop, genericSplitAt, )+import Data.Tuple.HT (mapFst, mapSnd, mapPair, swap, )+import Data.Maybe.HT (toMaybe, )++import Test.QuickCheck (Arbitrary(arbitrary), )++import NumericPrelude.Numeric+import NumericPrelude.Base+++{- |+The first pair member in @powerOfTwoFactors n@+is the maximum factor of @n@, that is a power of two.+-}+powerOfTwoFactors ::+ (Bits a, Integral.C a) => a -> (a, a)+powerOfTwoFactors n =+ let powerOfTwo = n .&. (-n)+ in (powerOfTwo, div n powerOfTwo)+++{- |+List all factorizations of an odd number+where the first factor is at most the second factor+and the first factors are in descending order.+-}+fermatFactors :: Integer -> [(Integer,Integer)]+fermatFactors n =+ let root = FP.sqrt 1 n+ in map (\(a,b) -> (b-a,b+a)) $+ mergeAndFilter+ (zip (scanl (+) n [1,3..]) [0 .. div (n-1) 2])+ (zip (scanl (+) (root*root) $ iterate (2+) (2*root+1)) [root..])++mergeAndFilter :: (Ord a) => [(a,b)] -> [(a,c)] -> [(b,c)]+mergeAndFilter ((a0,b):a0s) ((a1,c):a1s) =+ case compare a0 a1 of+ LT -> mergeAndFilter a0s ((a1,c):a1s)+ GT -> mergeAndFilter ((a0,b):a0s) a1s+ EQ -> (b,c) : mergeAndFilter a0s a1s+mergeAndFilter _ _ = []++++{- |+Argument must be a prime.+Usage of Set for efficient filtering of candidates seems to be overkill,+since the multiplicative generator seems to be small in most cases,+i.e. 2 or 3.+-}+multiplicativeGenerator :: Integer -> Integer+multiplicativeGenerator p =+ let search candidates =+ case Set.minView candidates of+ Nothing -> error $ show p ++ " is not an odd prime"+ Just (x,rest) ->+ case orbitSet $ orbit p x of+ new ->+ -- fromIntegral (Set.size new) == p-2+ if new == Set.fromList [1..p-1]+ then x+ else search (Set.difference rest new)+ in search (Set.fromList [2..p-1])+++newtype Order = Order {getOrder :: Integer}+ deriving (Show, Eq, Ord)++instance Arbitrary Order where+ arbitrary = fmap (Order . (1+) . abs) arbitrary++instance Enum Order where+ succ (Order n) = Order (n+1)+ pred (Order n) = Order (n-1)+ fromEnum (Order n) = fromEnum n+ toEnum n = Order (toEnum n)+ enumFrom (Order from) =+ map Order $ enumFrom from+ enumFromThen (Order from) (Order thn) =+ map Order $ enumFromThen from thn+ enumFromTo (Order from) (Order to) =+ map Order $ enumFromTo from to+ enumFromThenTo (Order from) (Order thn) (Order to) =+ map Order $ enumFromThenTo from thn to++countOrder :: [a] -> Order+countOrder = foldl (\o _ -> succ o) (Order 0)++dividesOrder :: Order -> Order -> Bool+dividesOrder (Order k) (Order n) =+ divides k n+++-- class Integral.C a => PrimitiveRoot a where+class PID.C a => PrimitiveRoot a where+ primitiveRootCandidates :: a -> [a]+ maximumOrderOfPrimitiveRootsOfUnity :: a -> Order++instance PrimitiveRoot Integer where+ primitiveRootCandidates modu = [1 .. modu-1]+ maximumOrderOfPrimitiveRootsOfUnity =+ maximumOrderOfPrimitiveRootsOfUnityInteger++{-+For 'ordersOfPrimitiveRootsOfUnityInteger'+and the connection to Euler's totient function+we have chosen to have++> primitiveRootsOfUnity m 1 == [1].+-}+primitiveRootsOfUnity ::+ (PrimitiveRoot a, Eq a) => a -> Order -> [a]+primitiveRootsOfUnity =+ primitiveRootsOfUnityPower++{-+Verifying that a ring has no primitive root of the wanted order+takes a long time if we do it by exhaustive search.+In the case of a=Integer we could first check,+whether the considered residue ring has a primitive root of wanted order+using the Carmichael function.+We could certainly count the number of primitive roots+and stop searching if we reach that count.+-}+primitiveRootsOfUnityPower ::+ (PrimitiveRoot a, Eq a) => a -> Order -> [a]+primitiveRootsOfUnityPower modu (Order order) =+ let greatDivisors = map (div order) $ uniquePrimeFactors order+ in filter+ (\n ->+ let pow y = RC.representative $ (n /: modu) ^ y+ in PID.coprime n modu+ &&+ pow order == one+ &&+ all (\y -> pow y /= one) greatDivisors) $+ primitiveRootCandidates modu++primitiveRootsOfUnityNaive ::+ (PrimitiveRoot a, Eq a) => a -> Order -> [a]+primitiveRootsOfUnityNaive _ (Order 0) = []+primitiveRootsOfUnityNaive modu (Order expo) =+ filter+ (\n ->+ let (prefix,end:_) =+ genericSplitAt (expo-1) $ SigS.toList $ orbit modu n+ in all (1/=) prefix && end==1) $+ primitiveRootCandidates modu++orbitSet :: Ord a => SigS.T a -> Set.Set a+orbitSet list =+ SigS.foldR+ (\new cont seen ->+ if Set.member new seen+ then seen+ else cont (Set.insert new seen))+ id list Set.empty++orbit :: (Integral.C a) => a -> a -> SigS.T a+orbit p x = SigS.iterate (\y -> mod (x*y) p) x+++{- |+Does not emit values in ascending order+and may return duplicates (e.g. primitiveRootsOfUnityFullOrbit 70000 10).+I hoped it would be faster than the other implementations+since it eliminates non-roots in large blocks.+However it seems that managing the root candidates in a Set+reduces performance significantly.++The idea:+Start with a seed that is a unit.+Compute its orbit until a one is reached.+Since it is a unit, we always encounter a one.+We do not need to check for non-unit seeds,+since (gcd modu seed) will be a divisor of all seed powers.+In the orbit all numbers are powers of each other.+Now finding the roots is a matter of solving+a Diophantine equation of the exponents.+In one such step all powers in an orbit are classified as roots or non-roots+and thus we can remove them all from the set of root candidates+and continue with the remaining candidates.+Duplicates can occur if a seed+in a later iteration is found again as power of another seed.+-}+primitiveRootsOfUnityFullOrbit ::+ (PrimitiveRoot a, Ord a) => a -> Order -> [a]+primitiveRootsOfUnityFullOrbit modu expo =+ let search candidates =+ flip fmap (Set.minView candidates) $ \(x,rest) ->+ mapSnd (Set.difference rest . Set.fromList) $+ primitiveRootsOfOrbit modu expo x+ in concat $ unfoldr search $ Set.fromList $+ -- needed for modules with many divisors+ filter (PID.coprime modu) $+ primitiveRootCandidates modu++primitiveRootsOfUnityFullOrbitTest ::+ (PrimitiveRoot a, Ord a) => a -> Order -> [(a,[a])]+primitiveRootsOfUnityFullOrbitTest modu expo =+ let search candidates =+ flip fmap (Set.minView candidates) $ \(x,rest) ->+ mapPair ((,) x,+ Set.difference rest . Set.fromList) $+ primitiveRootsOfOrbit modu expo x+ in unfoldr search $ Set.fromList $+ filter (PID.coprime modu) $+ primitiveRootCandidates modu++primitiveRootsOfOrbit ::+ (PrimitiveRoot a, Ord a) => a -> Order -> a -> ([a], [a])+primitiveRootsOfOrbit modu (Order expo) x =+ let orb = (1:) $ takeWhile (1/=) $ iterate (\y -> mod (x*y) modu) x+ (Order orbitSize) = countOrder orb+ in (if expo==0+ then []+ else+ {-+ size = length orb+ Search for m and k with 0<k and 0<m and m<size+ and expo*m = size*k+ such that for all l with 0<l and l<k+ m does not divide size*l.+ To this end we ask for every m+ for the smallest r such that size divides r*m.+ If r=expo then x^m is a primitive root of order expo.+ If r<expo then x^m has order smaller than expo.+ The searched r is div size (gcd size m).+ However expo = div size (gcd size m) implies,+ that expo is a divisor of size.+ expo = div size (gcd size m)+ => div size expo = gcd size m+ s = gcd size m+ We have to consider for m+ only the multiples of s.+ Then divide both sides of the equation by s, yielding+ 1 = gcd expo m'+ -}+ case divMod orbitSize expo of+ (s,0) ->+ map snd $ filter (PID.coprime expo . fst) $+ zip+ [0 .. expo-1]+ -- (ListHT.sieve s $ orb)+ (map head $ iterate (genericDrop s) orb)+ _ -> [],+ orb)+++hasPrimitiveRootOfUnityNaive ::+ (PrimitiveRoot a, Ord a) => a -> Order -> Bool+hasPrimitiveRootOfUnityNaive modu expo =+ any (dividesOrder expo . snd) $+ ordersOfPrimitiveRootsOfUnityTest modu++{-+This should be a maximum both with respect to magnitude and to divisibility.+-}+maximumOrderOfPrimitiveRootsOfUnityNaive ::+ (PrimitiveRoot a, Ord a) => a -> Order+maximumOrderOfPrimitiveRootsOfUnityNaive =+ foldl max (Order 1) . map snd . ordersOfPrimitiveRootsOfUnityTest++{- |+Computes a list of seeds and according maximum orders of roots of unity.+All divisors of those maximum orders are possible orders of roots of unity, too.+-}+ordersOfPrimitiveRootsOfUnityTest ::+ (PrimitiveRoot a, Ord a) => a -> [(a, Order)]+ordersOfPrimitiveRootsOfUnityTest modu =+ let search candidates =+ flip fmap (Set.minView candidates) $ \(x,rest) ->+ mapPair ((,) x,+ Set.difference rest . Set.fromList) $+ orderOfOrbit modu x+ in unfoldr search $ Set.fromList $+ filter (PID.coprime modu) $+ primitiveRootCandidates modu++{- |+modu and x must be coprime.+If they are not,+then none of the numbers in the orbit is a root of unity+and the function enters an infinite loop.+-}+orderOfOrbit ::+ (PrimitiveRoot a, Ord a) => a -> a -> (Order, [a])+orderOfOrbit modu x =+ let cyc = takeWhile (one/=) $ SigS.toList $ orbit modu x+ in (succ $ countOrder cyc, cyc)+++{-+This test speeds up 'hasPrimitiveRootOfUnityNaive' considerably+by considering the prime factors of modu.+If modu is a prime, then the ring has a multiplicative generator,+i.e. a primitive root of unity of order modu-1.+That is, all primitive roots of unity are of an order that divides modu-1.+It seems that if modu is a power of a prime,+then the according ring has also multiplicative generator.+I think this is the reason for generalising the Rader transform+to signals of prime power length.+-}+hasPrimitiveRootOfUnityInteger ::+ Integer -> Order -> Bool+hasPrimitiveRootOfUnityInteger modu expo =+ dividesOrder expo $+ maximumOrderOfPrimitiveRootsOfUnityInteger modu++{-+Carmichael theorem:+If the integer residue rings with coprime moduli m0 and m1+have primitive roots of maximum order o0 and o1, respectively,+then the integer ring with modulus m0*m1+has maximum order (lcm o0 o1).+-}++{-+This is the Carmichael function.+OEIS-A002322+-}+maximumOrderOfPrimitiveRootsOfUnityInteger ::+ Integer -> Order+maximumOrderOfPrimitiveRootsOfUnityInteger =+ Order .+ lcmMulti .+ map+ (\(e,p) ->+ if p == 2 && e > 2+ then p^(e-2)+ else p^(e-1) * (p-1)) .+ map (mapFst fromIntegral) .+ primeFactors+++{-+The sum of the sub-lists should equal the Euler totient function values+(OEIS-A000010).+-}+ordersOfPrimitiveRootsOfUnityInteger :: [[Int]]+ordersOfPrimitiveRootsOfUnityInteger =+ flip map [1..] $ \modu ->+ let maxOrder = maximumOrderOfPrimitiveRootsOfUnity (modu::Integer)+ in map (length . primitiveRootsOfUnityPower modu) $+-- filter (flip divides maxOrder) $+ [Order 1 .. maxOrder]++ordersOfRootsOfUnityInteger :: [[Int]]+ordersOfRootsOfUnityInteger =+ flip map [1..] $ \modu ->+ map (length . rootsOfUnityPower (modu::Integer)) $+ [Order 1 ..]+{-+mapM_ print $ map (\n -> (n, maximumOrderOfPrimitiveRootsOfUnityInteger (fromIntegral n), take 30 $ ordersOfRootsOfUnityInteger !! (n-1))) [2..30]++mapM_ print $ map (\n -> (n, maximumOrderOfPrimitiveRootsOfUnityInteger (fromIntegral n), let row = ordersOfRootsOfUnityInteger !! (n-1) in map (row!!) $ map pred $ take 10 $ iterate (2*) 1)) [2..30]+-}++ordersOfRootsOfUnityIntegerCondensed :: [[Int]]+ordersOfRootsOfUnityIntegerCondensed =+ flip map [1..] $ \modu ->+ let maxOrder = maximumOrderOfPrimitiveRootsOfUnity (modu::Integer)+ in map (length . rootsOfUnityPower modu) $+-- filter (flip divides maxOrder) $+ [Order 1 .. maxOrder]++rootsOfUnityPower ::+ (PrimitiveRoot a, Eq a) => a -> Order -> [a]+rootsOfUnityPower modu (Order expo) =+ filter+ (\n ->+ PID.coprime n modu+ &&+ RC.representative ((n /: modu) ^ expo) == one) $+ primitiveRootCandidates modu++{-+Corollary from the Carmichael function properties:+If in Z_n there is a primitive root r of unity of order o,+then for every Z_{m \cdot n} there is also a primitive root of unity+with the same order.++Collary:+If in Z_n1 you have a primitive root of order o1,+and so on for Z_{n_k} and order ok,+then Z_{lcm(n1,...,nk)} has primitive roots for every of the order o1,...,on.++Conjecture:+If Z_n has a total number of m primitive roots of unity of order o,+then Z_{k*n} has at least m primitive roots of unity of order o.++Conjecture:+Precondition: In Z_n there is a primitive root of prime order o.+Claims:+a) There are natural numbers m and k with n = m*(k*o+1) or n = m*o.+b) The smallest such n is of the form k*o+1 with k>1.++Counterexample for a) and non-prime o: o=15, n=77+Counterexample for b) and non-prime o:+ o=20, n=25; o=27, n=81; o=54, n=81; o=55, n=121++Corollary from definition of Carmichael function:+For n>1, Z_{2^{n+2}} has primitive root of unity of order 2^n.+-}++{- |+Given an order find integer residue rings+where roots of unity of this order exist.+The way they are constructed also warrants,+that 'order' is a unit (i.e. invertible) in those rings.++The list is not exhaustive+but computes suggestions quickly.+The first found modulus seems to be smallest one that exist.+However, the first modulus is not the smallest one+among the ones that only have the wanted primitive root,+but where 'order' is not necessarily a unit.+E.g.++> ringsWithPrimitiveRootOfUnityAndUnit 840 == 2521 : 3361 : ...++but the smallest modulus is 1763.++Most of the numbers are primes.+For these the recursion property of the Carmichael function+immediately yields that there are primitive roots of unity of order 'order'.+-}+ringsWithPrimitiveRootOfUnityAndUnit :: Order -> [Integer]+ringsWithPrimitiveRootOfUnityAndUnit order@(Order k) =+ filter (flip hasPrimitiveRootOfUnityInteger order) $+ iterate (k+) 1+++ringsWithPrimitiveRootsOfUnityAndUnitsNaive :: [Order] -> [Integer] -> [Integer]+ringsWithPrimitiveRootsOfUnityAndUnitsNaive rootOrders units =+ filter+ (\n ->+ all (hasPrimitiveRootOfUnityInteger n) rootOrders &&+ all (PID.coprime n) units)+ [1..]+++{-+It would be nice to have the Omega monad here+in order to enumerate all rings.+-}+ringWithPrimitiveRootsOfUnityAndUnits :: [Order] -> [Integer] -> Integer+ringWithPrimitiveRootsOfUnityAndUnits rootOrders units =+ let p = lcmMulti units+ in lcmMulti $+ map (head . filter (PID.coprime p) .+ ringsWithPrimitiveRootOfUnityAndUnit) $+ rootOrders++{-+Search for an appriopriate modulus+using the recursive definition of the Carmichael function.+We chose the prime factors of the Carmichael function argument+such that we get at least the prime factors in the function value that we need.++The modulus constructed this way is usually not the smallest possible+and it also does not provide that 'n' is a unit in the residue ring.+The simpler function 'ringsWithPrimitiveRootOfUnityAndUnit'+will usually produce a smaller modulus.+-}+ringWithPrimitiveRootsOfUnity :: Order -> Integer+ringWithPrimitiveRootsOfUnity (Order n) =+ case n of+ 0 -> 2+ _ ->+ product $ map (uncurry ringPower) $ snd $+ mapAccumL+ (\factors (e,p) ->+ if Map.findWithDefault 0 p factors >= e+ then (factors, (0,p))+ else+ if p==2+ then+ (factors,+ case e of+ 0 -> (0,2)+ 1 -> (1,3)+ 2 -> (1,5)+ _ -> (e+2, 2))+ else+ (Map.unionWith max factors $+ Map.fromList $ map swap $ primeFactors $ p-1,+ (e+1, p)))+ Map.empty $+ reverse $ primeFactors $ lcmMulti $+ n : map (subtract 1) (partialPrimes n)++lcmMulti :: (PID.C a) => [a] -> a+lcmMulti = foldl lcm one+++{- |+List all numbers that only contain prime factors 2 and 3 in ascending order.+OEIS:A003586+-}+numbers3Smooth :: [Integer]+numbers3Smooth =+ foldr+ (\(x0:x1:xs) ys -> x0 : x1 : ListHT.mergeBy (<=) xs ys)+ (error "numbers3Smooth: infinite list should not have an end") $+ iterate (map (3*)) $+ iterate (2*) 1++numbers3SmoothAlt :: [Integer]+numbers3SmoothAlt =+ unfoldr+ (fmap (\(m,rest) -> (m, Set.union rest $ Set.fromAscList [2*m,3*m])) .+ Set.minView) $+ Set.singleton 1++{-+OEIS:A051037+-}+numbers5Smooth :: [Integer]+numbers5Smooth =+ foldr+ (\(x0:x1:x2:xs) ys -> x0 : x1 : x2 : ListHT.mergeBy (<=) xs ys)+ (error "numbers5Smooth: infinite list should not have an end") $+ iterate (map (5*)) $+ numbers3Smooth++numbers5SmoothAlt :: [Integer]+numbers5SmoothAlt =+ unfoldr+ (fmap (\(m,rest) -> (m, Set.union rest $ Set.fromAscList [2*m,3*m,5*m])) .+ Set.minView) $+ Set.singleton 1++ceilingPowerOfTwo :: (Ring.C a, Bits a) => a -> a+ceilingPowerOfTwo 0 = 1+ceilingPowerOfTwo n =+ (1+) $ fst $ head $+ dropWhile (uncurry (/=)) $+ ListHT.mapAdjacent (,) $+ scanl (\m d -> shiftR m d .|. m) (n-1) $+ iterate (2*) 1++divideByMaximumPower ::+ (Integral.C a, ZeroTestable.C a) => a -> a -> a+divideByMaximumPower b n =+ last $+ n : unfoldr (\m -> case divMod m b of (q,r) -> toMaybe (isZero r) (q,q)) n++divideByMaximumPowerRecursive ::+ (Integral.C a, Eq a, ZeroTestable.C a) => a -> a -> a+divideByMaximumPowerRecursive b =+ let recourse n =+ case divMod b n of+ (q,0) -> recourse q+ _ -> n+ in recourse++getMaximumExponent ::+ (Integral.C a, ZeroTestable.C a) =>+ a -> a -> (Int,a)+getMaximumExponent b n =+ last $ (0,n) :+ unfoldr+ (\(e,m) ->+ let (q,r) = divMod m b+ eq = (e+1,q)+ in toMaybe (isZero r) (eq,eq))+ (0,n)++is3Smooth :: Integer -> Bool+is3Smooth =+ (1==) .+ divideByMaximumPower 3 .+ divideByMaximumPower 2++is5Smooth :: Integer -> Bool+is5Smooth =+ (1==) .+ divideByMaximumPower 5 .+ divideByMaximumPower 3 .+ divideByMaximumPower 2++{- |+Compute the smallest composite of 2 and 3 that is as least as large as the input.+This can be interpreted as solving an integer linear programming problem with+min (\(a,b) -> a * log 2 + b * log 3)+over the domain {(a,b) : a>=0, b>=0, a * log 2 + b * log 3 >= log n}+-}+{-+Problem: We cannot just start with the ceilingPowerOfTwo+and then multiply with 3/4 until we fall below n,+since the 3/4 decreases too fast.+27/32 is closer to one,+and higher powers of 3 and 2 in the ratio make the ratio even closer to one.+-}+ceiling3Smooth :: Integer -> Integer+ceiling3Smooth n =+ head $ dropWhile (<n) numbers3Smooth++ceiling5Smooth :: Integer -> Integer+ceiling5Smooth n =+ head $ dropWhile (<n) numbers5Smooth++ceiling3SmoothNaive :: Integer -> Integer+ceiling3SmoothNaive =+ head .+ dropWhile (not . is3Smooth) .+ iterate (1+)++ceiling5SmoothNaive :: Integer -> Integer+ceiling5SmoothNaive =+ head .+ dropWhile (not . is5Smooth) .+ iterate (1+)+++{- |+Compute all primes that occur in the course of dividing+a Fourier transform into sub-transforms.+-}+partialPrimes :: Integer -> [Integer]+partialPrimes =+ let primeFactorSet =+ Set.fromAscList . uniquePrimeFactors+ in unfoldr+ (fmap+ (\(p,set) ->+ (p, Set.union (primeFactorSet (p-1)) set)) .+ Set.maxView)+ .+ primeFactorSet++-- cf. htam:NumberTheory+uniquePrimeFactors ::+ (Integral.C a, Bits a, ZeroTestable.C a, Ord a) =>+ a -> [a]+-- map snd . primeFactors+uniquePrimeFactors n =+ let oddFactors =+ foldr+ (\p go m ->+ let (q,r) = divMod m p+ in if r==0+ then p : go (divideByMaximumPower p q)+ else+ if q >= p+ then go m+ else if m==1 then [] else m : [])+ (error "uniquePrimeFactors: end of infinite list")+ (iterate (2+) 3)+ in case powerOfTwoFactors n of+ (1,m) -> oddFactors m+ (_,m) -> 2 : oddFactors m++{- |+Prime factors and their exponents in ascending order.+-}+primeFactors ::+ (PrimitiveRoot a, Ord a) => a -> [(Int, a)]+primeFactors n =+ let oddFactors =+ foldr+ (\p go m ->+ let (q0,r) = divMod m p+ in if r==0+ then+ case getMaximumExponent p q0 of+ (e,q1) -> (e+1,p) : go q1+ else+ if q0 >= p+ then go m+ else if m==1 then [] else (1,m) : [])+ (const [])+ (filter (not . Units.isUnit) $+ primitiveRootCandidates n)+ in case getMaximumExponent 2 n of+ (0,m) -> oddFactors m+ (e,m) -> (e,2) : oddFactors m++{-+cf. htam:NumberTheory++Shall this be moved to NumericPrelude?++It should be replaced by a more sophisticated prime test.+-}+isPrime :: Integer -> Bool+isPrime n =+ case primeFactors n of+ [] -> False+ (e,m):_ -> e==1 && m==n++{- |+Find lengths of signals that require many interim Rader transforms+and end with the given length.++raderWorstCases 2 = OEIS-A061092+raderWorstCases 5 = tail OEIS-A059411++Smallest raderWorstCase numbers are 2,5,13,17,19,31,37,41,43,61,...+This matches the definition of OEIS-A061303.+-}+raderWorstCases :: Integer -> [Integer]+raderWorstCases =+ iterate+ (\n ->+ head $ dropWhile (not . isPrime) $+ tail $ iterate (n+) 1)++{- |+This is usually faster than 'fastFourierRing'+since it does not need to factor large numbers.+However, the generated modulus is usually much greater.+-}+{-+I see the following opportunities for optimization:++1. Speedup 'fastFourierRing' by+ faster primality test (Miller-Rabin) and+ faster prime factorization (Pollard-Rho-method).+ These are also needed for+ maximumOrderOfPrimitiveRootsOfUnityInteger+ that is used by Fourier.Element.primitiveRoot+ in order to compute a root with maximum order.++2. Reduce the moduli produced by 'fastFourierRingAlt'+ by merging some orders that are passed to+ ringWithPrimitiveRootsOfUnityAndUnits,+ such that an LCM of a group of orders can still be handled.+ This is a kind of knapsack problem.+ Maybe we could collect the factors in a way+ such that (lcm orderGroup + 1) is prime.++3. Avoid to compute factorizations of numbers+ where we already know the factors+ or where we do not need the factors at all.+ Use the factors returned by partialPrimes+ in order to compute a prime factorization+ of lcmMulti (map pred (partialPrimes n)).+ Call this (product ps).+ Now search for rings of moduli (1 + k * product ps),+ where there are (small) primitive roots of order (product ps).+ We only need to check whether there are small numbers+ such as 2, 3, 5, 6, 7 that have a (product ps)-th power that is 1,+ using fast exponentiation.+ If there is a power being 1 then check for primitivity+ by computing (k * product ps / p)-th powers+ for all prime factors p of (k * product ps).+ If there is no primitive root <= 7,+ there may still be a primitive root of wanted order,+ but it is then cheaper to seek for larger moduli.++ If we finally have a nice modulus+ it is still stupid to factorize (modulus-1)+ and search for a primitive root+ in each invocation of Fourier.Element.primitiveRoot.+ We could define a special datatype analogously to ResidueClass,+ that stores the primitive root and its order+ additional to the ResidueClass modulus.+-}+fastFourierRingAlt :: Int -> Integer+fastFourierRingAlt n =+ case n of+ 0 -> 2+ 1 -> 2+ _ ->+ let ni = fromIntegral n+ ps = filter (>1) (map (subtract 1) (partialPrimes ni))+ in ringWithPrimitiveRootsOfUnityAndUnits (map Order $ ni : ps) ps++{- |+Determine an integer residue ring+in which a Fast Fourier transform of size n can be performed.+It must contain certain primitive roots.+If we choose a non-primitive root,+then some off-diagonal values in F^-1·F are non-zero.+-}+{-+When we need roots of orders o1,...,ok and according inverse elements+we can also ask for a ring, where there is a root of order lcm(o1,...,ok).+The answer to both questions is the same set of rings.+This can be proven using the statement,+that the order of any primitive root+divides the carmichael value of the modulus.++Since ringWithPrimitiveRootsOfUnityAndUnits+multiplies the moduli of rings for o1,...,ok,+it will produce large moduli.+-}+fastFourierRing :: Int -> Integer+fastFourierRing n =+ case n of+ 0 -> 2+ 1 -> 2+ _ ->+ let ni = fromIntegral n+ in {-+ We cannot use ringsWithPrimitiveRootOfUnityAndUnit+ since for 359 we already get an Int overflow.+ For 719, 1439, 2879 we also get a very large value.+ -}+ head $ filter isPrime $+ (\order -> iterate (order +) 1) $+ lcmMulti $+ ni : map (subtract 1) (partialPrimes ni)
src/Synthesizer/Basic/ToneModulation.hs view
@@ -5,16 +5,11 @@ import Synthesizer.Interpolation (Margin, marginOffset, marginNumber, ) --- import qualified Algebra.Transcendental as Trans import qualified Algebra.RealField as RealField import qualified Algebra.Field as Field--- import qualified Algebra.RealRing as RealRing import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import NumericPrelude.Numeric---- import qualified Prelude as P import NumericPrelude.Base
+ src/Synthesizer/Causal/Analysis.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE NoImplicitPrelude #-}+module Synthesizer.Causal.Analysis where++import qualified Synthesizer.Causal.Filter.Recursive.Integration as Integration++import qualified Synthesizer.Causal.Process as Causal+import qualified Synthesizer.Plain.Analysis as Ana++import qualified Algebra.RealRing as RealRing++import Control.Arrow (second, (^<<), (<<^), )++-- import qualified Prelude as P+import NumericPrelude.Base+import NumericPrelude.Numeric+++deltaSigmaModulation ::+ RealRing.C y => Causal.T y Ana.BinaryLevel+deltaSigmaModulation =+ Causal.feedback+ ((Ana.binaryLevelFromBool . (zero <=)) ^<<+ Integration.run <<^+ uncurry (-))+ (Causal.consInit zero <<^ Ana.binaryLevelToNumber)++deltaSigmaModulationPositive ::+ RealRing.C y => Causal.T (y, y) y+deltaSigmaModulationPositive =+ Causal.feedback+ ((\(threshold,xi) -> if threshold<=xi then threshold else zero) ^<<+ second Integration.run <<^+ (\((threshold,xi),cum) -> (threshold,xi-cum)))+ (Causal.consInit zero)
src/Synthesizer/Causal/Displacement.hs view
@@ -7,7 +7,6 @@ import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Causal/Interpolation.hs view
@@ -24,8 +24,6 @@ import qualified Algebra.RealRing as RealRing import qualified Algebra.Additive as Additive -import Algebra.Additive(zero)- import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Causal/Oscillator.hs view
@@ -29,13 +29,10 @@ import qualified Algebra.Transcendental as Trans import qualified Algebra.RealField as RealField import qualified Algebra.RealRing as RealRing-import qualified Algebra.Ring as Ring -import Control.Arrow ((^<<), (<<^), (<<<), (***), second, )+import Control.Arrow ((^<<), (<<^), (<<<), (***), ) import NumericPrelude.Numeric--import qualified Prelude as P import NumericPrelude.Base
src/Synthesizer/Causal/Oscillator/Core.hs view
@@ -21,13 +21,10 @@ import qualified Synthesizer.State.Signal as Sig import qualified Algebra.RealRing as RealRing-import qualified Algebra.Additive as Additive import Control.Arrow ((^<<), (&&&), second, returnA, ) import NumericPrelude.Numeric--import qualified Prelude as P import NumericPrelude.Base
+ src/Synthesizer/Causal/Spatial.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE NoImplicitPrelude #-}+module Synthesizer.Causal.Spatial where++import qualified Algebra.NormedSpace.Euclidean as Euc+import qualified Algebra.Field as Field++import Control.Arrow (Arrow, arr, )++import NumericPrelude.Base+import NumericPrelude.Numeric+++{-|+simulate an moving sounding object++convert the way of the object through 3D space+into a delay and attenuation information,+sonicDelay is the reciprocal of the sonic velocity+-}+receive3Dsound ::+ (Field.C a, Euc.C a v, Arrow arrow) =>+ a -> a -> v -> arrow v (a,a)+receive3Dsound att sonicDelay ear =+ arr ((\dist -> (sonicDelay*dist, 1/(att+dist)^2)) . Euc.norm . subtract ear)
src/Synthesizer/ChunkySize/Cut.hs view
@@ -9,45 +9,24 @@ import qualified Synthesizer.Generic.Cut as Cut import qualified Synthesizer.Generic.Signal as SigG --- import qualified Synthesizer.Plain.Signal as Sig import qualified Synthesizer.State.Signal as SigS--- import qualified Synthesizer.Storable.Signal as SigSt import qualified Data.StorableVector.Lazy.Pattern as SigStV import qualified Data.StorableVector.Lazy as Vector -import qualified Algebra.Ring as Ring--- import qualified Algebra.ToInteger as ToInteger---- import qualified Number.NonNegative as NonNegW--- import qualified Algebra.NonNegative as NonNeg import qualified Number.NonNegativeChunky as Chunky -{---- import qualified Numeric.NonNegative.Wrapper as NonNegW98-import qualified Numeric.NonNegative.Class as NonNeg98-import qualified Numeric.NonNegative.Chunky as Chunky98--}- import Foreign.Storable (Storable) import qualified Data.List as List import qualified Data.List.Match as Match import Data.Tuple.HT (mapPair, ) -import qualified Data.Monoid as Monoid import Data.Monoid (Monoid, ) -import qualified Prelude as P+import Prelude () import NumericPrelude.Numeric import NumericPrelude.Base hiding (splitAt, Read, )-{--import Prelude- (Bool, Int, String, (++), error, const,- pred, (<=), (>=), (<), (>), ($),- (.), not, (||), (&&),- Maybe(Just, Nothing), )--} class Cut.Read sig => Read sig where
src/Synthesizer/ChunkySize/Signal.hs view
@@ -14,10 +14,6 @@ import qualified Data.StorableVector.Lazy.Pattern as SigStV import qualified Data.StorableVector.Lazy as Vector --- import qualified Algebra.NonNegative as NonNeg--- import qualified Algebra.Module as Module--- import qualified Algebra.Additive as Additive- import Foreign.Storable (Storable) import qualified Data.List.Match as Match@@ -28,7 +24,7 @@ -- import NumericPrelude.Numeric import Prelude- (Bool, Int, Maybe(Just), fst, (.), id, )+ (Maybe(Just), fst, (.), id, ) class (SigG.Write sig y, Cut.Transform (sig y)) => Write sig y where
src/Synthesizer/Generic/Analysis.hs view
@@ -8,31 +8,15 @@ import qualified Synthesizer.Generic.Signal as SigG import qualified Synthesizer.Generic.Signal2 as SigG2 --- import qualified Synthesizer.Plain.Control as Ctrl---- import qualified Algebra.Module as Module--- import qualified Algebra.Transcendental as Trans import qualified Algebra.Algebraic as Algebraic--- import qualified Algebra.RealField as RealField import qualified Algebra.Field as Field import qualified Algebra.RealRing as RealRing-import qualified Algebra.Absolute as Absolute import qualified Algebra.Ring as Ring-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 Data.Array as Array---- import qualified Data.IntMap as IntMap---- import Algebra.Module((*>))---- import Data.Array (accumArray)--import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric @@ -310,18 +294,16 @@ then not(x<lower) else x>upper) -{- {- | Almost naive implementation of the chirp transform, a generalization of the Fourier transform. More sophisticated algorithms like Rader, Cooley-Tukey, Winograd, Prime-Factor may follow. -}-chirpTransform :: Ring.C y =>- y -> sig y -> sig y-chirpTransform z xs =- let powers = Ctrl.curveMultiscaleNeutral (*) z one- powerPowers =- SigG.map (\zn -> Ctrl.curveMultiscaleNeutral (*) zn one) powers- in SigG.map (scalarProduct xs) powerPowers--}+chirpTransform ::+ (SigG.Write sig y, Ring.C y) =>+ SigG.LazySize -> y -> sig y -> sig y+chirpTransform size z =+ SigG.fromState size .+ Ana.chirpTransform z .+ SigG.toState
src/Synthesizer/Generic/Control.hs view
@@ -12,17 +12,11 @@ import qualified Algebra.Transcendental as Trans import qualified Algebra.RealRing as RealRing import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import Algebra.Module((*>))- import Number.Complex (cis,real) import qualified Number.Complex as Complex --- import Control.Applicative ((<$>), )--import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Generic/Cut.hs view
@@ -11,21 +11,18 @@ import qualified Synthesizer.State.Signal as SigS -- import qualified Synthesizer.Storable.Signal as SigSt import qualified Data.StorableVector as SV-import qualified Data.StorableVector.Lazy as Vector+import qualified Data.StorableVector.Lazy as SVL import qualified Algebra.ToInteger as ToInteger import qualified Algebra.Ring as Ring import qualified Data.EventList.Relative.BodyTime as EventList --- import qualified Number.NonNegative as NonNegW import qualified Algebra.NonNegative as NonNeg import qualified Number.NonNegativeChunky as Chunky --- import qualified Numeric.NonNegative.Wrapper as NonNegW98 import qualified Numeric.NonNegative.Class as NonNeg98 import qualified Numeric.NonNegative.Chunky as Chunky98-import Numeric.NonNegative.Class ((-|), ) import Foreign.Storable (Storable, ) import Control.DeepSeq (NFData, rnf, )@@ -41,10 +38,10 @@ import qualified Prelude as P import NumericPrelude.Numeric import Prelude- (Bool, Int, String, (++), error,+ (Bool, String, (++), error, pred, (<=), (>=), (<), (.), ($), const, snd,- not, (||), (&&), min, )+ not, (||), (&&), min, max, ) class Read sig where@@ -81,48 +78,74 @@ reverse :: sig -> sig +instance Storable y => Read (SV.Vector y) where+ {-# INLINE null #-}+ null = SV.null+ {-# INLINE length #-}+ length = SV.length++instance (Storable y) => NormalForm (SV.Vector y) where+ {-# INLINE evaluateHead #-}+ evaluateHead x =+ if SV.null x then () else ()++instance Storable y => Transform (SV.Vector y) where+ {-# INLINE take #-}+ take = SV.take+ {-# INLINE drop #-}+ drop = SV.drop+ {-# INLINE splitAt #-}+ splitAt = SV.splitAt+ {-# INLINE dropMarginRem #-}+ dropMarginRem n m xs =+ let d = min m $ max 0 $ SV.length xs - n+ in (m-d, SV.drop d xs)+ {-# INLINE reverse #-}+ reverse = SV.reverse++ -- instance Storable y => Read SigSt.T y where-instance Storable y => Read (Vector.Vector y) where+instance Storable y => Read (SVL.Vector y) where {-# INLINE null #-}- null = Vector.null+ null = SVL.null {-# INLINE length #-}- length = Vector.length+ length = SVL.length -instance (Storable y) => NormalForm (Vector.Vector y) where+instance (Storable y) => NormalForm (SVL.Vector y) where {-# INLINE evaluateHead #-} evaluateHead =- ListHT.switchL () (\x _ -> if SV.null x then () else ()) . Vector.chunks--- ListHT.switchL () (\x _ -> rnf x) . Vector.chunks+ ListHT.switchL () (\x _ -> evaluateHead x) . SVL.chunks+-- ListHT.switchL () (\x _ -> rnf x) . SVL.chunks -- evaluateHead x =--- if Vector.null x then () else ()+-- if SVL.null x then () else () {--instance (Storable y, NFData y) => NormalForm (Vector.Vector y) where+instance (Storable y, NFData y) => NormalForm (SVL.Vector y) where {-# INLINE evaluateHead #-}- evaluateHead x = Vector.switchL () (\x _ -> rnf x)+ evaluateHead x = SVL.switchL () (\x _ -> rnf x) -} -instance Storable y => Transform (Vector.Vector y) where+instance Storable y => Transform (SVL.Vector y) where {- {-# INLINE empty #-}- empty = Vector.empty+ empty = SVL.empty {-# INLINE cycle #-}- cycle = Vector.cycle+ cycle = SVL.cycle {-# INLINE append #-}- append = Vector.append+ append = SVL.append {-# INLINE concat #-}- concat = Vector.concat+ concat = SVL.concat -} {-# INLINE take #-}- take = Vector.take+ take = SVL.take {-# INLINE drop #-}- drop = Vector.drop+ drop = SVL.drop {-# INLINE splitAt #-}- splitAt = Vector.splitAt+ splitAt = SVL.splitAt {-# INLINE dropMarginRem #-}- dropMarginRem = Vector.dropMarginRem+ dropMarginRem = SVL.dropMarginRem {-# INLINE reverse #-}- reverse = Vector.reverse+ reverse = SVL.reverse instance Read ([] y) where@@ -301,8 +324,8 @@ dropMarginRem n m x = let (z,~(b,d)) = Chunky.minMaxDiff- (intToChunky "dropMargin/n" n)- (x NonNeg.-| intToChunky "dropMargin/m" m)+ (intToChunky "dropMargin/n" m)+ (x NonNeg.-| intToChunky "dropMargin/m" n) in (if b then 0 else fromIntegral (Chunky.toNumber d), x NonNeg.-| z) {-# INLINE splitAt #-}@@ -346,8 +369,8 @@ dropMarginRem n m x = let (z,~(b,d)) = NonNeg98.split- (intToChunky98 "dropMargin/n" n)- (x NonNeg98.-| intToChunky98 "dropMargin/m" m)+ (intToChunky98 "dropMargin/n" m)+ (x NonNeg98.-| intToChunky98 "dropMargin/m" n) in (if b then 0 else P.fromIntegral (Chunky98.toNumber d), x NonNeg98.-| z) {-# INLINE splitAt #-}
+ src/Synthesizer/Generic/Cyclic.hs view
@@ -0,0 +1,192 @@+module Synthesizer.Generic.Cyclic where++import qualified Synthesizer.Generic.Filter.NonRecursive as FiltNRG+import qualified Synthesizer.Generic.Analysis as AnaG+import qualified Synthesizer.Generic.Signal2 as SigG2+import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.State.Signal as Sig++import qualified Algebra.Ring as Ring+import qualified Algebra.Additive as Additive++import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()+++fromSignal ::+ (SigG.Write sig yv, Additive.C yv) =>+ SigG.LazySize -> Int -> sig yv -> sig yv+fromSignal chunkSize n =+ {- almost Sig.sum -}+ Sig.foldL SigG.mix (SigG.replicate chunkSize n zero) .+ CutG.sliceVertical n++reverse ::+ (SigG.Transform sig y) =>+ sig y -> sig y+reverse sig =+ SigG.switchL sig+ (\y ys -> SigG.cons y (SigG.reverse ys)) sig+++{- |+It must hold @n <= CutG.length x@.+-}+reperiodize ::+ (SigG.Transform sig yv, Additive.C yv) =>+ Int -> sig yv -> sig yv+reperiodize n =+ {- Sig.sum -}+ Sig.foldL SigG.mix CutG.empty .+ CutG.sliceVertical n++{- |+length of the input signals must be equal+-}+convolve ::+ (SigG2.Transform sig y y, Ring.C y) =>+ sig y -> sig y -> sig y+convolve x y =+ reperiodize (CutG.length x) $+ FiltNRG.karatsubaFinite (*) x y++++{- |+The size of both input signals must be equal.++Could be optimized by computing only first (length x) elements.+-}+filterNaive ::+ (SigG.Transform sig y, Ring.C y) =>+ sig y -> sig y -> sig y+filterNaive x y =+ SigG.takeStateMatch y $+ SigG.toState $+ SigG.mapTails+ (AnaG.scalarProduct x)+ (SigG.append y y)++convolveNaive ::+ (SigG.Transform sig y, Ring.C y) =>+ sig y -> sig y -> sig y+convolveNaive x y =+ SigG.takeStateMatch y $+ SigG.toState $+ SigG.mapTails+ (AnaG.scalarProduct (SigG.reverse x))+ (SigG.laxTail $ SigG.append y y)+++{-+Some small size convolutions using the Karatsuba trick.+We do not use Toom-3 multiplication,+because this requires division by 2 and 6.++In principle we could implement them+by calling the corresponding functions in Filter.NonRecursive+and periodize them afterwards.+However the custom implementations below+allow a litte bit more optimization,+namely sharing of some sums.+-}++type Pair y = (y,y)++{-# INLINE convolvePair #-}+convolvePair ::+ (Ring.C y) =>+ Pair y -> Pair y -> Pair y+convolvePair a b =+ snd $ sumAndConvolvePair a b++{-# INLINE sumAndConvolvePair #-}+sumAndConvolvePair ::+ (Ring.C y) =>+ Pair y -> Pair y -> ((y,y), Pair y)+sumAndConvolvePair (a0,a1) (b0,b1) =+ let sa01 = a0+a1+ sb01 = b0+b1+ ab0ab1 = a0*b0+a1*b1+ in ((sa01, sb01), (ab0ab1, sa01*sb01-ab0ab1))+++type Triple y = (y,y,y)++{-# INLINE convolveTriple #-}+convolveTriple ::+ (Ring.C y) =>+ Triple y -> Triple y -> Triple y+convolveTriple a b =+ snd $ sumAndConvolveTriple a b++{-# INLINE sumAndConvolveTriple #-}+sumAndConvolveTriple ::+ (Ring.C y) =>+ Triple y -> Triple y -> ((y,y), Triple y)+sumAndConvolveTriple (a0,a1,a2) (b0,b1,b2) =+ let ab0 = a0*b0+ dab12 = a1*b1 - a2*b2+ sa01 = a0+a1; sb01 = b0+b1; tab01 = sa01*sb01 - ab0+ sa02 = a0+a2; sb02 = b0+b2; tab02 = sa02*sb02 - ab0+ sa012 = sa01+a2+ sb012 = sb01+b2++ d0 = sa012*sb012 - tab01 - tab02+ d1 = tab01 - dab12+ d2 = tab02 + dab12+ in ((sa012, sb012), (d0, d1, d2))++{-# INLINE sumAndConvolveTripleAlt #-}+sumAndConvolveTripleAlt ::+ (Ring.C y) =>+ Triple y -> Triple y -> ((y,y), Triple y)+sumAndConvolveTripleAlt (a0,a1,a2) (b0,b1,b2) =+ let ab0 = a0*b0+ ab1 = a1*b1+ ab2 = a2*b2+ sa01 = a0+a1; sb01 = b0+b1+ ab01 = sa01*sb01 - (ab0+ab1)+ sa02 = a0+a2; sb02 = b0+b2+ ab02 = sa02*sb02 - (ab0+ab2)+ sa12 = a1+a2; sb12 = b1+b2+ ab12 = sa12*sb12 - (ab1+ab2)+ in ((sa01+a2, sb01+b2), (ab0+ab12, ab2+ab01, ab1+ab02))+++type Quadruple y = (y,y,y,y)++{-# INLINE convolveQuadruple #-}+convolveQuadruple ::+ (Ring.C y) =>+ Quadruple y -> Quadruple y -> Quadruple y+convolveQuadruple a b =+ snd $ sumAndConvolveQuadruple a b++{-# INLINE sumAndConvolveQuadruple #-}+sumAndConvolveQuadruple ::+ (Ring.C y) =>+ Quadruple y -> Quadruple y -> ((y,y), Quadruple y)+sumAndConvolveQuadruple (a0,a1,a2,a3) (b0,b1,b2,b3) =+ let ab0 = a0*b0+ ab1 = a1*b1+ sa01 = a0+a1; sb01 = b0+b1+ ab01 = sa01*sb01 - (ab0+ab1)+ ab2 = a2*b2+ ab3 = a3*b3+ sa23 = a2+a3; sb23 = b2+b3+ ab23 = sa23*sb23 - (ab2+ab3)+ c0 = ab0 + ab2 - (ab1 + ab3)+ c1 = ab01 + ab23+ ab02 = (a0+a2)*(b0+b2)+ ab13 = (a1+a3)*(b1+b3)+ sa0123 = sa01+sa23+ sb0123 = sb01+sb23+ ab0123 = sa0123*sb0123 - (ab02+ab13)+ d0 = ab13 + c0+ d1 = c1+ d2 = ab02 - c0+ d3 = ab0123 - c1+ in ((sa0123, sb0123), (d0, d1, d2, d3))
src/Synthesizer/Generic/Filter/NonRecursive.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE FlexibleContexts #-} {- |-Copyright : (c) Henning Thielemann 2008-2009+Copyright : (c) Henning Thielemann 2008-2011 License : GPL Maintainer : synthesizer@henning-thielemann.de@@ -12,8 +12,10 @@ import qualified Synthesizer.Generic.Signal as SigG import qualified Synthesizer.Generic.Signal2 as SigG2-+import qualified Synthesizer.Generic.Cut as CutG import qualified Synthesizer.Generic.Control as Ctrl+import qualified Synthesizer.Generic.LengthSignal as SigL+ import qualified Synthesizer.State.Signal as SigS import qualified Synthesizer.Plain.Filter.NonRecursive as Filt import qualified Synthesizer.State.Filter.NonRecursive as FiltS@@ -25,8 +27,6 @@ import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import Algebra.Module( {- linearComb, -} (*>), )- import Control.Monad (mplus, ) import Data.Function.HT (nest, ) import Data.Tuple.HT (mapSnd, mapPair, )@@ -36,7 +36,7 @@ import NumericPrelude.Numeric as NP -{- * Envelope application -}+-- * Envelope application {-# INLINE negate #-} negate ::@@ -99,7 +99,7 @@ envelope leadOut partOut -{- * Smoothing -}+-- * Delay {-# INLINE delay #-} delay :: (Additive.C y, SigG.Write sig y) =>@@ -153,6 +153,7 @@ SigG.append (SigG.replicate size n zero) +-- * smoothing binomialMask :: (Field.C a, SigG.Write sig a) =>@@ -169,16 +170,6 @@ property: must sum up to 1 -} -{-| Unmodulated non-recursive filter -}-{-# INLINE generic #-}-generic ::- (Module.C a v, SigG.Transform sig a, SigG.Write sig v) =>- sig a -> sig v -> sig v-generic m x =- let mr = SigG.reverse m- xp = delayPos (pred (SigG.length m)) x- in SigG.mapTails (SigG.linearComb mr) xp- {- {- | @eps@ is the threshold relatively to the maximum.@@ -588,3 +579,335 @@ (Additive.C v, SigG.Transform sig v) => sig v -> sig v differentiate2 = differentiate . differentiate+++-- * general non-recursive filters++{-|+Unmodulated non-recursive filter (convolution)++Brute force implementation.+-}+{-# INLINE generic #-}+generic ::+ (Module.C a v, SigG.Transform sig a, SigG.Write sig v) =>+ sig a -> sig v -> sig v+generic m x =+ if SigG.null m || SigG.null x+ then CutG.empty+ else+ let mr = SigG.reverse m+ xp = delayPos (pred (SigG.length m)) x+ in SigG.mapTails (SigG.linearComb mr) xp+++{- |+Both should signals should have similar length.+If they have considerably different length,+then better use 'karatsubaFiniteInfinite'.++Implementation using Karatsuba trick and split-and-overlap-add.+This way we stay in a ring, are faster than quadratic runtime+but do not reach log-linear runtime.+-}+karatsubaFinite ::+ (Additive.C a, Additive.C b, Additive.C c,+ SigG2.Transform sig a c, SigG2.Transform sig b c) =>+ (a -> b -> c) ->+ sig a -> sig b -> sig c+karatsubaFinite mul a b =+ SigL.toSignal $+ karatsubaBounded mul+ (SigL.fromSignal a) (SigL.fromSignal b)++{-# INLINE karatsubaBounded #-}+karatsubaBounded ::+ (Additive.C a, Additive.C b, Additive.C c,+ SigG2.Transform sig a c, SigG2.Transform sig b c) =>+ (a -> b -> c) ->+ SigL.T (sig a) -> SigL.T (sig b) -> SigL.T (sig c)+karatsubaBounded mul a b =+ case (SigL.length a, SigL.length b) of+ (0,_) -> CutG.empty+ (_,0) -> CutG.empty+ (1,_) ->+ SigG.switchL+ (error "karatsubaBounded: empty signal")+ (\y _ -> fmap (SigG2.map (mul y)) b) $+ SigL.body a+ (_,1) ->+ SigG.switchL+ (error "karatsubaBounded: empty signal")+ (\y _ -> fmap (SigG2.map (flip mul y)) a) $+ SigL.body b+ (2,2) ->+ let [a0,a1] = SigG.toList (SigL.toSignal a)+ [b0,b1] = SigG.toList (SigL.toSignal b)+ (c0,c1,c2) = convolvePair mul (a0,a1) (b0,b1)+ in SigL.Cons 3 $ rechunk a b $+ c0 : c1 : c2 : []+ (2,3) ->+ let [a0,a1] = SigG.toList (SigL.toSignal a)+ [b0,b1,b2] = SigG.toList (SigL.toSignal b)+ (c0,c1,c2,c3) =+ convolvePairTriple mul (a0,a1) (b0,b1,b2)+ in SigL.Cons 4 $ rechunk a b $+ c0 : c1 : c2 : c3 : []+ (3,2) ->+ let [a0,a1,a2] = SigG.toList (SigL.toSignal a)+ [b0,b1] = SigG.toList (SigL.toSignal b)+ (c0,c1,c2,c3) =+ convolvePairTriple (flip mul) (b0,b1) (a0,a1,a2)+ in SigL.Cons 4 $ rechunk a b $+ c0 : c1 : c2 : c3 : []+ (3,3) ->+ let [a0,a1,a2] = SigG.toList (SigL.toSignal a)+ [b0,b1,b2] = SigG.toList (SigL.toSignal b)+ (c0,c1,c2,c3,c4) =+ convolveTriple mul (a0,a1,a2) (b0,b1,b2)+ in SigL.Cons 5 $ rechunk a b $+ c0 : c1 : c2 : c3 : c4 : []+ (4,4) ->+ let [a0,a1,a2,a3] = SigG.toList (SigL.toSignal a)+ [b0,b1,b2,b3] = SigG.toList (SigL.toSignal b)+ (c0,c1,c2,c3,c4,c5,c6) =+ convolveQuadruple mul (a0,a1,a2,a3) (b0,b1,b2,b3)+ in SigL.Cons 7 $ rechunk a b $+ c0 : c1 : c2 : c3 : c4 : c5 : c6 : []+ (lenA,lenB) ->+ let n2 = div (max lenA lenB) 2+ (a0,a1) = SigL.splitAt n2 a+ (b0,b1) = SigL.splitAt n2 b+ (c0,c1,c2) =+ convolvePair+ (karatsubaBounded mul)+ (a0,a1) (b0,b1)+ in fmap (rechunk a b) $+ SigL.addShiftedSimple n2 c0 $+ SigL.addShiftedSimple n2 c1 c2++{-# INLINE rechunk #-}+rechunk ::+ (SigG2.Transform sig1 a c, SigG2.Transform sig1 b c,+ SigG.Transform sig0 c) =>+ SigL.T (sig1 a) -> SigL.T (sig1 b) -> sig0 c -> sig1 c+rechunk a b c =+ let (ac,bc) = CutG.splitAt (SigL.length a) c+ in SigG2.takeStateMatch (SigL.body a) (SigG.toState ac)+ `SigG.append`+ SigG2.takeStateMatch (SigL.body b) (SigG.toState bc)+++{- |+The first operand must be finite and+the second one can be infinite.+For efficient operation we expect that the second signal+is longer than the first one.+-}+{-+Implemented by overlap-add of pieces that are convolved by Karatsuba trick.+Is it more efficient to round the chunk size up to the next power of two?+Can we make use of the fact,+that the first operand is always split in the same way?+-}+karatsubaFiniteInfinite ::+ (Additive.C a, Additive.C b, Additive.C c,+ SigG2.Transform sig a c, SigG2.Transform sig b c) =>+ (a -> b -> c) ->+ sig a -> sig b -> sig c+karatsubaFiniteInfinite mul a b =+ let al = SigL.fromSignal a+ in case SigL.length al of+ 0 -> CutG.empty+ alen ->+ SigS.foldR (addShiftedSimple alen) CutG.empty $+ SigS.map SigL.toSignal $+ SigS.map (karatsubaBounded mul al . SigL.fromSignal) $+ SigG.sliceVertical alen b+++karatsubaInfinite ::+ (Additive.C a, Additive.C b, Additive.C c,+ SigG2.Transform sig a c, SigG2.Transform sig b c) =>+ (a -> b -> c) ->+ sig a -> sig b -> sig c+karatsubaInfinite mul =+ let recourse n a b =+ let (a0,a1) = SigG.splitAt n a+ (b0,b1) = SigG.splitAt n b+ {-+ We could also apply Karatsuba's trick to these pairs.+ But this requires Additive (sig a) constraint+ and I do not know whether this is actually an optimization.+ -}+ ab00 =+ SigL.toSignal $+ karatsubaBounded mul+ (SigL.fromSignal a0) (SigL.fromSignal b0)+ ab01 = karatsubaFiniteInfinite mul a0 b1+ ab10 = karatsubaFiniteInfinite (flip mul) b0 a1+ ab11 = recourse (2*n) a1 b1+ in if SigG.null a || SigG.null b+ then CutG.empty+ else+ addShiftedSimple n ab00 $+ addShiftedSimple n (SigG.mix ab01 ab10) ab11+ in recourse 1+++{- |+It must hold @delay <= length a@.+-}+{-+It is crucial that 'mix' uses the chunk size structure of the second operand.+This way we avoid unnecessary and even infinite look-ahead.+-}+{-# INLINE addShiftedSimple #-}+addShiftedSimple ::+ (Additive.C a, SigG.Transform sig a) =>+ Int -> sig a -> sig a -> sig a+addShiftedSimple del a b =+ uncurry CutG.append $+ mapSnd (flip SigG.mix b) $+ CutG.splitAt del a+++-- ** hard-wired convolutions for small sizes++{-+Some small size convolutions using the Karatsuba trick.+We do not use Toom-3 multiplication,+because this requires division by 2 and 6.+With Karatsuba we can stay in a ring.+-}++type Pair a = (a,a)++{- |+Reasonable choices for the multiplication operation are '(*)', '(*>)', 'convolve'.+-}+{-# INLINE convolvePair #-}+convolvePair ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Pair a -> Pair b -> Triple c+convolvePair mul a b =+ snd $ sumAndConvolvePair mul a b++{-# INLINE sumAndConvolvePair #-}+sumAndConvolvePair ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Pair a -> Pair b -> ((a,b), Triple c)+sumAndConvolvePair (!*!) (a0,a1) (b0,b1) =+ let sa01 = a0+a1+ sb01 = b0+b1+ ab0 = a0!*!b0+ ab1 = a1!*!b1+ in ((sa01, sb01), (ab0, sa01!*!sb01-(ab0+ab1), ab1))++type Triple a = (a,a,a)++{-# INLINE convolvePairTriple #-}+convolvePairTriple ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Pair a -> Triple b -> (c,c,c,c)+convolvePairTriple (!*!) (a0,a1) (b0,b1,b2) =+ let ab0 = a0!*!b0+ ab1 = a1!*!b1+ sa01 = a0+a1; sb01 = b0+b1; ab01 = sa01!*!sb01+ in (ab0, ab01 - (ab0+ab1),+ a0!*!b2 + ab1, a1!*!b2)+++{-# INLINE convolveTriple #-}+convolveTriple ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Triple a -> Triple b -> (c,c,c,c,c)+convolveTriple mul a b =+ snd $ sumAndConvolveTriple mul a b++{-# INLINE sumAndConvolveTriple #-}+sumAndConvolveTriple ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Triple a -> Triple b -> ((a,b), (c,c,c,c,c))+sumAndConvolveTriple (!*!) (a0,a1,a2) (b0,b1,b2) =+ let ab0 = a0!*!b0+ ab1 = a1!*!b1+ ab2 = a2!*!b2+ sa01 = a0+a1; sb01 = b0+b1; ab01 = sa01!*!sb01+ sa02 = a0+a2; sb02 = b0+b2; ab02 = sa02!*!sb02+ sa012 = sa01+a2+ sb012 = sb01+b2+ in ((sa012, sb012),+ (ab0, ab01 - (ab0+ab1),+ ab02 + ab1 - (ab0+ab2),+ sa012!*!sb012 - ab02 - ab01 + ab0, ab2))++{-# INLINE sumAndConvolveTripleAlt #-}+sumAndConvolveTripleAlt ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Triple a -> Triple b -> ((a,b), (c,c,c,c,c))+sumAndConvolveTripleAlt (!*!) (a0,a1,a2) (b0,b1,b2) =+ let ab0 = a0!*!b0+ ab1 = a1!*!b1+ ab2 = a2!*!b2+ sa01 = a0+a1; sb01 = b0+b1+ ab01 = sa01!*!sb01 - (ab0+ab1)+ sa02 = a0+a2; sb02 = b0+b2+ ab02 = sa02!*!sb02 - (ab0+ab2)+ sa12 = a1+a2; sb12 = b1+b2+ ab12 = sa12!*!sb12 - (ab1+ab2)+ in ((sa01+a2, sb01+b2),+ (ab0, ab01, ab1+ab02, ab12, ab2))++type Quadruple a = (a,a,a,a)++{-# INLINE convolveQuadruple #-}+convolveQuadruple ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Quadruple a -> Quadruple b -> (c,c,c,c,c,c,c)+convolveQuadruple mul a b =+ snd $ sumAndConvolveQuadruple mul a b++{-# INLINE sumAndConvolveQuadruple #-}+sumAndConvolveQuadruple ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Quadruple a -> Quadruple b -> ((a,b), (c,c,c,c,c,c,c))+sumAndConvolveQuadruple (!*!) (a0,a1,a2,a3) (b0,b1,b2,b3) =+ let ab0 = a0!*!b0+ ab1 = a1!*!b1+ sa01 = a0+a1; sb01 = b0+b1+ ab01 = sa01!*!sb01 - (ab0+ab1)+ ab2 = a2!*!b2+ ab3 = a3!*!b3+ sa23 = a2+a3; sb23 = b2+b3+ ab23 = sa23!*!sb23 - (ab2+ab3)+ ab02 = (a0+a2)!*!(b0+b2)+ ab13 = (a1+a3)!*!(b1+b3)+ sa0123 = sa01+sa23+ sb0123 = sb01+sb23+ ab0123 = sa0123!*!sb0123 - (ab02+ab13)+ in ((sa0123, sb0123),+ (ab0, ab01, ab1+ab02-(ab0+ab2),+ ab0123 - (ab01+ab23),+ ab2+ab13-(ab1+ab3), ab23, ab3))++{-# INLINE sumAndConvolveQuadrupleAlt #-}+sumAndConvolveQuadrupleAlt ::+ (Additive.C a, Additive.C b, Additive.C c) =>+ (a -> b -> c) ->+ Quadruple a -> Quadruple b -> ((a,b), (c,c,c,c,c,c,c))+sumAndConvolveQuadrupleAlt mul (a0,a1,a2,a3) (b0,b1,b2,b3) =+ let (((sa02,sa13), (sb02,sb13)),+ ((c00,c01,c02), (c10,c11,c12), (c20,c21,c22))) =+ sumAndConvolvePair (convolvePair mul)+ ((a0,a1),(a2,a3)) ((b0,b1),(b2,b3))+ in ((sa02+sa13, sb02+sb13),+ (c00,c01,c02+c10,c11,c12+c20,c21,c22))
src/Synthesizer/Generic/Filter/Recursive/Comb.hs view
@@ -19,11 +19,9 @@ import qualified Synthesizer.Generic.Signal as SigG 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 qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
+ src/Synthesizer/Generic/Fourier.hs view
@@ -0,0 +1,997 @@+{- |+Complete implementation for Fast Fourier Transform for any signal length.+Although defined for all kinds of signal storage,+we need fast access to arbitrary indices.+-}+{-+further thoughts+ - Test the algorithms using remainder polynomials+ with respect to [-1,0,...,0,1]+ Problem: We would need large polynomial degrees,+ namely LCM of the size of all sub-transforms.+ Those numbers are in the same magnitude+ as the integers we use for our integer residue class arithmetic.+ - a z-transform by convolving with a chirp would be nice,+ however we need a square of the primitive root of unity+ in order to compute cis((i/n)^2/2)+ - Can we write the Fourier transforms for lengths larger than the input signal length+ with implicit zero padding?+ This would be useful for Fourier based convolution.+ Our frequent use of 'rechunk' would be a problem, though.+ transformCoprime also needs explicit zero padding.+ - a type class could unify all Level generators+ and thus they would allow for a generic way to call a certain sub-transform+-}+{-# LANGUAGE NoImplicitPrelude #-}+module Synthesizer.Generic.Fourier (+ Element(..),+ -- * conversion between time and frequency domain (spectrum)+ transformForward,+ transformBackward,+ cacheForward,+ cacheBackward,+ cacheDuplex,+ transformWithCache,+ -- * convolution based on Fourier transform+ convolveCyclic,+ Window,+ window,+ convolveWithWindow,+ ) where++import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.Generic.Cyclic as Cyclic+import qualified Synthesizer.Generic.Filter.NonRecursive as FiltNRG++import qualified Synthesizer.Generic.Permutation as Permutation+import qualified Synthesizer.Basic.NumberTheory as NumberTheory++import qualified Synthesizer.State.Analysis as Ana+import qualified Synthesizer.State.Signal as SigS++import qualified Algebra.Transcendental as Trans+-- import qualified Algebra.Field as Field+import qualified Algebra.Ring as Ring+import qualified Algebra.PrincipalIdealDomain as PID+import qualified Algebra.IntegralDomain as Integral++import qualified Number.ResidueClass.Check as RC+import Number.ResidueClass.Check ((/:), )++import qualified Number.Complex as Complex+import Number.Complex ((+:))++import qualified Data.Map as Map+import qualified Control.Monad.Trans.State as State+import Control.Monad (liftM2, )+import Control.Applicative ((<$>), )++import Data.Tuple.HT (mapPair, )++import NumericPrelude.Numeric+import NumericPrelude.Base hiding (head, )++++class Ring.C y => Element y where+ recipInteger :: (SigG.Read sig y) => sig y -> y+ addId :: (SigG.Read sig y) => sig y -> y+ multId :: (SigG.Read sig y) => sig y -> y+ {- |+ It must hold:++ > uncurry (*) (conjugatePrimitiveRootsOfUnity n) = 1++ > mapPair ((^m), (^m)) (conjugatePrimitiveRootsOfUnity (n*m) y)+ > == conjugatePrimitiveRootsOfUnity n y@++ since we need for caching that the cache is uniquely determined+ by singal length and transform direction.+ -}+ conjugatePrimitiveRootsOfUnity :: (SigG.Read sig y) => sig y -> (y,y)++instance Trans.C a => Element (Complex.T a) where+ recipInteger sig = recip (fromIntegral (SigG.length sig)) +: zero+ addId _sig = zero+ multId _sig = one+ conjugatePrimitiveRootsOfUnity sig =+ (\x -> (x, Complex.conjugate x)) $+ case SigG.length sig of+ 1 -> one+ 2 -> negate one+ 3 -> (negate one +: sqrt 3) / 2+ 4 -> zero +: one+ 5 ->+ let sqrt5 = sqrt 5+ in ((sqrt5 - 1) +: sqrt 2 * sqrt(5 + sqrt5)) / 4+ 6 -> (one +: sqrt 3) / 2+ 8 -> Complex.scale (sqrt 2 / 2) (one +: one)+ 12 -> (sqrt 3 +: one) / 2+ n -> Complex.cis (2*pi / fromIntegral n)++instance (NumberTheory.PrimitiveRoot a, PID.C a, Eq a) => Element (RC.T a) where+ recipInteger sig =+ recip (fromIntegral (SigG.length sig) /: RC.modulus (head sig))+ addId sig = zero /: RC.modulus (head sig)+ multId sig = one /: RC.modulus (head sig)+ {-+ We cannot simply compute+ NumberTheory.primitiveRootsOfUnity modu (SigG.length sig)+ since we have to fulfill the laws.+ In order to fulfill them,+ we choose a root with maximum order,+ this will always be the same,+ and it is a root of all primitive roots+ of any possible order in that ring.+ -}+ conjugatePrimitiveRootsOfUnity sig =+ let modu = RC.modulus (head sig)+ order@(NumberTheory.Order expo) =+ NumberTheory.maximumOrderOfPrimitiveRootsOfUnity modu+ r:_ = NumberTheory.primitiveRootsOfUnity modu order+ n = Integral.divChecked expo (fromIntegral (SigG.length sig))+ z = (r /: modu) ^ n+ in (z, recip z)+++head :: (SigG.Read sig y) => sig y -> y+head =+ SigG.switchL (error "Generic.Signal.head: empty signal") const .+ SigG.toState+++directionPrimitiveRootsOfUnity ::+ (Element y, SigG.Read sig y) =>+ sig y -> ((Direction,y), (Direction,y))+directionPrimitiveRootsOfUnity x =+ let (z,zInv) =+ conjugatePrimitiveRootsOfUnity x+ in ((Forward,z), (Backward,zInv))++transformForward ::+ (Element y, SigG.Transform sig y) =>+ sig y -> sig y+transformForward xs =+ transformWithCache (cacheForward xs) xs++{- |+Shall we divide the result values by the length of the signal?+Our dimensional wrapper around the Fourier transform does not expect this.+-}+transformBackward ::+ (Element y, SigG.Transform sig y) =>+ sig y -> sig y+transformBackward xs =+ transformWithCache (cacheBackward xs) xs++{- |+The size of the signal must match the size, that the plan was generated for.+-}+_transformPlan ::+ (Element y, SigG.Transform sig y) =>+ Plan -> (Direction,y) -> sig y -> sig y+_transformPlan p z xs =+ transformWithCache (cacheFromPlan p z xs) xs++{- |+The size and type of the signal must match the parameters,+that the cache was generated for.+-}+transformWithCache ::+ (Element y, SigG.Transform sig y) =>+ Cache sig y -> sig y -> sig y+transformWithCache cache xs =+ case cache of+ CacheIdentity -> xs+ CacheSmall size ->+ case size of+ LevelCache2 zs -> transform2 zs xs+ LevelCache3 zs -> transform3 zs xs+ LevelCache4 zs -> transform4 zs xs+ LevelCache5 zs -> transform5 zs xs+ CacheNaive level ->+ transformNaive level xs+ CacheRadix2 level subCache ->+ transformRadix2InterleavedFrequency level subCache xs+ CachePrime level subCaches ->+ transformPrime level subCaches xs+ CacheCoprime level subCaches ->+ transformCoprime level subCaches xs+ CacheComposite level subCaches ->+ transformComposite level subCaches xs+++{- |+Memorize factorizations of the data size and permutation vectors.+-}+data Plan =+ PlanIdentity+ | PlanSmall LevelSmall+ | PlanNaive -- mainly for debugging+ | PlanRadix2 LevelRadix2 Plan+ | PlanPrime LevelPrime Plan+ | PlanCoprime LevelCoprime (Plan, Plan)+ | PlanComposite LevelComposite (Plan, Plan)+ deriving (Show)++{-+efficient swallow comparison+only correct for Plans generated by 'plan'.+-}+instance Eq Plan where+ p0 == p1 = compare p0 p1 == EQ++{-+Needed for keys in CacheMap+-}+instance Ord Plan where+ compare p0 p1 =+ case (p0,p1) of+ (PlanIdentity, PlanIdentity) -> EQ+ (PlanIdentity, _) -> LT+ (_, PlanIdentity) -> GT+ (PlanSmall l0, PlanSmall l1) -> compare l0 l1+ (PlanSmall _, _) -> LT+ (_, PlanSmall _) -> GT+ (PlanNaive, PlanNaive) -> EQ+ (PlanNaive, _) -> LT+ (_, PlanNaive) -> GT+ (PlanRadix2 l0 _, PlanRadix2 l1 _) -> compare l0 l1+ (PlanRadix2 _ _, _) -> LT+ (_, PlanRadix2 _ _) -> GT+ (PlanPrime l0 _, PlanPrime l1 _) -> compare l0 l1+ (PlanPrime _ _, _) -> LT+ (_, PlanPrime _ _) -> GT+ (PlanCoprime l0 _, PlanCoprime l1 _) -> compare l0 l1+ (PlanCoprime _ _, _) -> LT+ (_, PlanCoprime _ _) -> GT+ (PlanComposite l0 _, PlanComposite l1 _) -> compare l0 l1+++plan :: Integer -> Plan+plan n =+ State.evalState (planWithMapUpdate n) smallPlanMap++type PlanMap = Map.Map Integer Plan++smallPlanMap :: PlanMap+smallPlanMap =+ Map.fromAscList $ zip [0..] $+ PlanIdentity :+ PlanIdentity :+ PlanSmall Level2 :+ PlanSmall Level3 :+ PlanSmall Level4 :+ PlanSmall Level5 :+ []++{- |+Detect and re-use common sub-plans.+-}+planWithMap :: Integer -> State.State PlanMap Plan+planWithMap n =+ case divMod n 2 of+ (n2,0) -> PlanRadix2 (levelRadix2 n2) <$> planWithMapUpdate n2+ _ ->+ let facs = NumberTheory.fermatFactors n+ in -- find unitary divisors+ case filter (\(a,b) -> a>1 && gcd a b == 1) facs of+ q2 : _ ->+ PlanCoprime (levelCoprime q2) <$>+ planWithMapUpdate2 q2+ _ ->+ let (q2 : _) = facs+ in if fst q2 == 1+ then PlanPrime (levelPrime $ snd q2) <$>+ planWithMapUpdate (n-1)+ else PlanComposite (levelComposite q2) <$>+ planWithMapUpdate2 q2++planWithMapUpdate :: Integer -> State.State PlanMap Plan+planWithMapUpdate n = do+ item <- State.gets (Map.lookup n)+ case item of+ Just p -> return p+ Nothing ->+ planWithMap n >>= \m -> State.modify (Map.insert n m) >> return m++planWithMapUpdate2 :: (Integer, Integer) -> State.State PlanMap (Plan, Plan)+planWithMapUpdate2 =+ uncurry (liftM2 (,)) .+ mapPair (planWithMapUpdate,planWithMapUpdate)+++{- |+Cache powers of the primitive root of unity+in a storage compatible to the processed signal.+-}+data Cache sig y =+ CacheIdentity+ | CacheSmall (LevelCacheSmall y)+ | CacheNaive (LevelCacheNaive y)+ | CacheRadix2 (LevelCacheRadix2 sig y) (Cache sig y)+ | CachePrime (LevelCachePrime sig y) (Cache sig y, Cache sig y)+ | CacheCoprime LevelCoprime (Cache sig y, Cache sig y)+ | CacheComposite (LevelCacheComposite sig y) (Cache sig y, Cache sig y)+ deriving (Show)++{- |+The expression @cacheForward prototype@+precomputes all data that is needed for forward Fourier transforms+for signals of the type and length @prototype@.+You can use this cache in 'transformWithCache'.+-}+cacheForward ::+ (Element y, SigG.Transform sig y) =>+ sig y -> Cache sig y+cacheForward xs =+ cacheFromPlan+ (plan $ fromIntegral $ SigG.length xs)+ (fst $ directionPrimitiveRootsOfUnity xs)+ xs++{- |+See 'cacheForward'.+-}+cacheBackward ::+ (Element y, SigG.Transform sig y) =>+ sig y -> Cache sig y+cacheBackward xs =+ cacheFromPlan+ (plan $ fromIntegral $ SigG.length xs)+ (snd $ directionPrimitiveRootsOfUnity xs)+ xs++{- |+It is @(cacheForward x, cacheBackward x) = cacheDuplex x@+but 'cacheDuplex' shared common data of both caches.+-}+cacheDuplex ::+ (Element y, SigG.Transform sig y) =>+ sig y -> (Cache sig y, Cache sig y)+cacheDuplex xs =+ let p = plan $ fromIntegral $ SigG.length xs+ (z,zInv) = directionPrimitiveRootsOfUnity xs+ in State.evalState+ (cacheFromPlanWithMapUpdate2 (p,p) (z,zInv) (xs,xs)) $+ Map.empty+++data Direction = Forward | Backward+ deriving (Show, Eq, Ord)++type CacheMap sig y = Map.Map (Plan,Direction) (Cache sig y)++cacheFromPlan ::+ (Element y, SigG.Transform sig y) =>+ Plan -> (Direction, y) -> sig y -> Cache sig y+cacheFromPlan p z xs =+ State.evalState (cacheFromPlanWithMapUpdate p z xs) $+ Map.empty++{- |+Detect and re-use common sub-caches.+-}+cacheFromPlanWithMap ::+ (Element y, SigG.Transform sig y) =>+ Plan -> (Direction,y) -> sig y ->+ State.State (CacheMap sig y) (Cache sig y)+cacheFromPlanWithMap p (d,z) xs =+ case p of+ PlanIdentity -> return $ CacheIdentity+ PlanSmall size -> return $ CacheSmall $+ case size of+ Level2 -> LevelCache2 $ cache2 z+ Level3 -> LevelCache3 $ cache3 z+ Level4 -> LevelCache4 $ cache4 z+ Level5 -> LevelCache5 $ cache5 z+ PlanNaive ->+ return $ CacheNaive $ LevelCacheNaive z+ PlanRadix2 level@(LevelRadix2 n2) subPlan ->+ let subxs = CutG.take n2 xs+ in CacheRadix2 (levelCacheRadix2 level z subxs) <$>+ cacheFromPlanWithMapUpdate subPlan (d,z*z) subxs+ PlanPrime level@(LevelPrime (perm,_,_)) subPlan ->+ (\subCaches ->+ CachePrime+ (levelCachePrime level (fst subCaches) z xs) subCaches)+ <$>+ let subxs = CutG.take (Permutation.size perm) xs+ in cacheFromPlanWithMapUpdate2 (subPlan,subPlan)+ (directionPrimitiveRootsOfUnity subxs)+ (subxs,subxs)+ PlanCoprime level@(LevelCoprime (n,m) _) subPlans ->+ CacheCoprime level <$>+ cacheFromPlanWithMapUpdate2 subPlans ((d,z^m), (d,z^n))+ (CutG.take (fromInteger n) xs, CutG.take (fromInteger m) xs)+ PlanComposite level@(LevelComposite (n,m) _) subPlans ->+ CacheComposite (levelCacheComposite level z xs) <$>+ cacheFromPlanWithMapUpdate2 subPlans ((d,z^m), (d,z^n))+ (CutG.take (fromInteger n) xs, CutG.take (fromInteger m) xs)++cacheFromPlanWithMapUpdate ::+ (Element y, SigG.Transform sig y) =>+ Plan -> (Direction,y) -> sig y ->+ State.State (CacheMap sig y) (Cache sig y)+cacheFromPlanWithMapUpdate p z xs = do+ let key = (p, fst z)+ item <- State.gets (Map.lookup key)+ case item of+ Just c -> return c+ Nothing ->+ cacheFromPlanWithMap p z xs >>= \m ->+ State.modify (Map.insert key m) >>+ return m++cacheFromPlanWithMapUpdate2 ::+ (Element y, SigG.Transform sig y) =>+ (Plan, Plan) -> ((Direction,y),(Direction,y)) -> (sig y, sig y) ->+ State.State (CacheMap sig y) (Cache sig y, Cache sig y)+cacheFromPlanWithMapUpdate2 (p0,p1) (z0,z1) (xs0,xs1) =+ liftM2 (,)+ (cacheFromPlanWithMapUpdate p0 z0 xs0)+ (cacheFromPlanWithMapUpdate p1 z1 xs1)+++newtype LevelCacheNaive y =+ LevelCacheNaive y+ deriving (Show)++transformNaive ::+ (Element y, SigG.Transform sig y) =>+ LevelCacheNaive y -> sig y -> sig y+transformNaive (LevelCacheNaive z) sig =+ SigG.takeStateMatch sig $+ SigS.map+ (scalarProduct1 (SigG.toState sig) . powers sig)+ (powers sig z)++scalarProduct1 ::+ (Ring.C a) =>+ SigS.T a -> SigS.T a -> a+scalarProduct1 xs ys =+ SigS.foldL1 (+) $ SigS.zipWith (*) xs ys++_transformRing ::+ (Ring.C y, SigG.Transform sig y) =>+ y -> sig y -> sig y+_transformRing z sig =+ SigG.takeStateMatch sig $+ Ana.chirpTransform z $ SigG.toState sig++powers ::+ (Element y, SigG.Read sig y) =>+ sig y -> y -> SigS.T y+powers sig c = SigS.iterate (c*) $ multId sig+++data LevelSmall = Level2 | Level3 | Level4 | Level5+ deriving (Show, Eq, Ord, Enum)++data LevelCacheSmall y =+ LevelCache2 y+ | LevelCache3 (y,y)+ | LevelCache4 (y,y,y)+ | LevelCache5 (y,y,y,y)+ deriving (Show)++cache2 :: (Ring.C y) => y -> y+cache3 :: (Ring.C y) => y -> (y,y)+cache4 :: (Ring.C y) => y -> (y,y,y)+cache5 :: (Ring.C y) => y -> (y,y,y,y)++cache2 z = z+cache3 z = (z, z*z)+cache4 z = let z2=z*z in (z,z2,z*z2)+cache5 z = let z2=z*z in (z,z2,z*z2,z2*z2)+++transform2 ::+ (Ring.C y, SigG.Transform sig y) =>+ y -> sig y -> sig y+transform2 z sig =+ let x0:x1:_ = SigG.toList sig+ in SigG.takeStateMatch sig $+ SigS.fromList [x0+x1, x0+z*x1]++transform3 ::+ (Ring.C y, SigG.Transform sig y) =>+ (y,y) -> sig y -> sig y+transform3 (z,z2) sig =+ let x0:x1:x2:_ = SigG.toList sig+{- Rader's algorithm with convolution by 2-size-Fourier-transform+ xf1 = x1+x2+ xf2 = x1-x2+ zf1 = z+z2+ zf2 = z-z2+ xzf1 = xf1*zf1+ xzf2 = xf2*zf2+ xz1 = (xzf1+xzf2)/2+ xz2 = (xzf1-xzf2)/2+-}+{- naive+ [x0+x1+x2, x0+z*x1+z2*x2, x0+z2*x1+z*x2]+-}+ ((s,_), (zx1,zx2)) = Cyclic.sumAndConvolvePair (x1,x2) (z,z2)+ in SigG.takeStateMatch sig $+ SigS.fromList [x0+s, x0+zx1, x0+zx2]++transform4 ::+ (Ring.C y, SigG.Transform sig y) =>+ (y,y,y) -> sig y -> sig y+transform4 (z,z2,z3) sig =+ let x0:x1:x2:x3:_ = SigG.toList sig+ x02a = x0+x2; x02b = x0+z2*x2+ x13a = x1+x3; x13b = x1+z2*x3+ in SigG.takeStateMatch sig $+ SigS.fromList [x02a+ x13a, x02b+z *x13b,+ x02a+z2*x13a, x02b+z3*x13b]+{-+This needs also five multiplications,+but in complex numbers it is z=i, and thus multiplications are cheap+and we should better make use of distributive law in order to save additions.++ x02a = x0+x2; x02b = x0+z2*x2+ x1_2 = z2*x1; x3_2 = z2*x3+ in SigG.takeStateMatch sig $+ SigS.fromList [x02a + x1 + x3 , x02b+z*(x1 + x3_2),+ x02a + x1_2 + x3_2, x02b+z*(x1_2 + x3 )]+-}++{-+Use Rader's trick for mapping the transform to a convolution+and apply Karatsuba's trick at two levels (i.e. total three times)+to that convolution.++0 0 0 0 0+0 1 2 3 4+0 2 4 1 3+0 3 1 4 2+0 4 3 2 1++Permutation.T: 0 1 2 4 3++0 0 0 0 0+0 1 2 4 3+0 2 4 3 1+0 4 3 1 2+0 3 1 2 4+-}+transform5 ::+ (Ring.C y, SigG.Transform sig y) =>+ (y,y,y,y) -> sig y -> sig y+transform5 (z1,z2,z3,z4) sig =+ let x0:x1:x2:x3:x4:_ = SigG.toList sig+ ((s,_), (d1,d2,d4,d3)) =+ Cyclic.sumAndConvolveQuadruple (x1,x3,x4,x2) (z1,z2,z4,z3)+ in SigG.takeStateMatch sig $+ SigS.fromList [x0+s, x0+d1, x0+d2, x0+d3, x0+d4]++{-+transform7++Toom-3-multiplication at the highest level and Karatsuba below?+Toom-2.5-multiplication with manual addition of the missing parts?++Toom-3-multiplication with complex interpolation nodes?+Still requires division by 4 and then complex multiplication in the frequency domain.+A:=matrix(5,5,[1,0,0,0,0,1,1,1,1,1,1,-1,1,-1,1,1,I,-1,-I,1,0,0,0,0,1]);+A:=matrix(5,5,[1,0,0,0,0,1,1,1,1,1,1,-1,1,-1,1,1,I,-1,-I,1,1,-I,-1,I,1]);++Karatsuba at three levels for convolution of signal of size 8 with zero padding?++Modify the 3x3 Fourier matrix by multiplying a regular matrix+to make it more convenient to work with?+We will hardly get rid of the irrational numbers.+-}++newtype LevelRadix2 = LevelRadix2 Int+ deriving (Show, Eq, Ord)++levelRadix2 :: Integer -> LevelRadix2+levelRadix2 =+ LevelRadix2 . fromIntegral+++data LevelCacheRadix2 sig y =+ LevelCacheRadix2 Int (sig y)+ deriving (Show)++levelCacheRadix2 ::+ (Element y, SigG.Transform sig y) =>+ LevelRadix2 -> y -> sig y -> LevelCacheRadix2 sig y+levelCacheRadix2 (LevelRadix2 n2) z sig =+ LevelCacheRadix2 n2+ (SigG.takeStateMatch sig $ powers sig z)+++{- |+Cooley-Tukey specialised to one factor of the size being 2.++Size of the input signal must be even.+-}+transformRadix2InterleavedFrequency ::+ (Element y, SigG.Transform sig y) =>+ LevelCacheRadix2 sig y -> Cache sig y -> sig y -> sig y+transformRadix2InterleavedFrequency+ (LevelCacheRadix2 n2 twiddle) subCache sig =+ let (xs0,xs1) = SigG.splitAt n2 sig+ fs0 = transformWithCache subCache $ SigG.zipWith (+) xs0 xs1+ fs1 = transformWithCache subCache $+ SigG.zipWith3+ (\w x0 x1 -> w*(x0-x1))+ twiddle xs0 xs1+ in SigG.takeStateMatch sig $+ SigS.interleave (SigG.toState fs0) (SigG.toState fs1)+++data LevelComposite =+ LevelComposite+ (Integer, Integer)+ (Permutation.T, Permutation.T)+ deriving (Show)++instance Eq LevelComposite where+ a == b = compare a b == EQ++instance Ord LevelComposite where+ compare (LevelComposite a _) (LevelComposite b _) =+ compare a b++levelComposite :: (Integer, Integer) -> LevelComposite+levelComposite (n,m) =+ let ni = fromInteger n+ mi = fromInteger m+ in LevelComposite (n,m)+ (Permutation.transposition ni mi,+ Permutation.transposition mi ni)+++data LevelCacheComposite sig y =+ LevelCacheComposite+ (Integer, Integer)+ (Permutation.T, Permutation.T)+ (sig y)+ deriving (Show)++levelCacheComposite ::+ (Element y, SigG.Transform sig y) =>+ LevelComposite -> y -> sig y -> LevelCacheComposite sig y+levelCacheComposite (LevelComposite (n,m) transpose) z sig =+ LevelCacheComposite (n,m) transpose $+ SigG.takeStateMatch sig $+ flip SigS.generateInfinite (n, multId sig, multId sig) $ \(i,zi,zij) ->+ (zij,+ case pred i of+ 0 -> (n, zi*z, multId sig)+ i1 -> (i1, zi, zij*zi))+{-+ {-# SCC "levelCacheComposite:rechunk" #-}+ concatRechunk sig $+ {-# SCC "levelCacheComposite:subpowers" #-}+ SigS.map+ (SigG.takeStateMatch (SigG.take (fromIntegral n) sig) . powers sig)+ ({-# SCC "levelCacheComposite:powers" #-}+ powers sig z)+-}+{-+ SigS.map+ (SigG.takeStateMatch sig . SigS.take (fromIntegral n) . powers sig)+ ({-# SCC "levelCacheComposite:powers" #-}+ powers sig z)+-}+{- suffers from big inefficiency of repeated 'append'+ SigG.takeStateMatch sig $+ SigS.monoidConcat $+ SigS.map (SigS.take (fromIntegral n) . powers sig) $+ SigS.take (fromIntegral m) $ -- necessary for strict storable vectors+ powers sig z+-}++{- |+For @transformComposite z (n,m) sig@,+the parameters @n@ and @m@ must be relatively prime+and @n*m == length sig@ and @z ^ length sig == 1@.++Cooley-Tukey-algorithm+-}+transformComposite ::+ (Element y, SigG.Transform sig y) =>+ LevelCacheComposite sig y -> (Cache sig y, Cache sig y) -> sig y -> sig y+transformComposite+ (LevelCacheComposite (n,m) (transposeNM, transposeMN) twiddle)+ (subCacheN,subCacheM) sig =+ Permutation.apply transposeMN .+ concatRechunk sig .+ SigS.map (transformWithCache subCacheM) .+ SigG.sliceVertical (fromInteger m) .+ Permutation.apply transposeNM .+-- concatRechunk sig .+ SigG.zipWith (*) twiddle .+ SigS.monoidConcat .+ SigS.map (transformWithCache subCacheN) .+ SigG.sliceVertical (fromInteger n) .+ Permutation.apply transposeMN $+ sig+++data LevelCoprime =+ LevelCoprime+ (Integer, Integer)+ (Permutation.T, Permutation.T, Permutation.T)+ deriving (Show)++instance Eq LevelCoprime where+ a == b = compare a b == EQ++instance Ord LevelCoprime where+ compare (LevelCoprime a _) (LevelCoprime b _) =+ compare a b++{-+Fourier exponent matrix of a signal of size 6.++0 0 0 0 0 0 0 0 0 0 0 0+0 1 2 3 4 5 0 2 0 4 3 0+0 2 4 0 2 4 = 0 * 0 2 4 * 0 0+0 3 0 3 0 3 0 0 0 0 0 3+0 4 2 0 4 2 0 0 4 2 0 0+0 5 4 3 2 1 0 4 0 2 0 3+-}+levelCoprime :: (Integer, Integer) -> LevelCoprime+levelCoprime (n,m) =+ let ni = fromInteger n+ mi = fromInteger m+ in LevelCoprime (n,m)+ (Permutation.skewGrid mi ni,+ Permutation.transposition ni mi,+ Permutation.skewGridCRTInv ni mi)+++{- |+For @transformCoprime z (n,m) sig@,+the parameters @n@ and @m@ must be relatively prime+and @n*m == length sig@ and @z ^ length sig == 1@.++Good-Thomas algorithm+-}+{-+A very elegant way would be to divide the signal into chunks of size n,+define ring operations on these chunks+and perform one (length/n)-size-sub-transform in this chunk-ring.+This way we would also only have to plan the sub-transform once.+On StorableVectors the chunking could be performed in-place+in terms of a virtual reshape operation.+In the general case the performance can become very bad+if the chunks are very small, say 2 or 3 elements.+-}+transformCoprime ::+ (Element y, SigG.Transform sig y) =>+ LevelCoprime -> (Cache sig y, Cache sig y) -> sig y -> sig y+transformCoprime+ (LevelCoprime (n,m) (grid, transpose, gridInv)) (subCacheN,subCacheM) =+ let subTransform cache j sig =+ concatRechunk sig .+ SigS.map (transformWithCache cache) .+ SigG.sliceVertical (fromIntegral j) $ sig+ in Permutation.apply gridInv .+ subTransform subCacheM m .+ Permutation.apply transpose .+ subTransform subCacheN n .+ Permutation.apply grid+++-- concatenate and reorganize for faster indexing+concatRechunk ::+ (SigG.Transform sig y) =>+ sig y -> SigS.T (sig y) -> sig y+concatRechunk pattern =+ SigG.takeStateMatch pattern .+ SigG.toState .+ SigS.monoidConcat+++data LevelPrime =+ LevelPrime (Permutation.T, Permutation.T, Permutation.T)+ deriving (Show)++instance Eq LevelPrime where+ a == b = compare a b == EQ++instance Ord LevelPrime where+ compare (LevelPrime (a,_,_)) (LevelPrime (b,_,_)) =+ compare (Permutation.size a) (Permutation.size b)++{-+Fourier exponent matrix of a signal of size 7.++0 0 0 0 0 0 0+0 1 2 3 4 5 6+0 2 4 6 1 3 5+0 3 6 2 5 1 4+0 4 1 5 2 6 3+0 5 3 1 6 4 2+0 6 5 4 3 2 1++multiplicative generator in Z7: 3+permutation of rows and columns by powers of 3: 1 3 2 6 4 5++0 0 0 0 0 0 0+0 1 3 2 6 4 5+0 3 2 6 4 5 1+0 2 6 4 5 1 3+0 6 4 5 1 3 2+0 4 5 1 3 2 6+0 5 1 3 2 6 4++Inverse permutation: 1 3 2 5 6 4+The inverse permutations seems not to be generated by a multiplication.+-}+levelPrime :: Integer -> LevelPrime+levelPrime n =+ let perm = Permutation.multiplicative $ fromIntegral n+ in LevelPrime+ (perm, Permutation.reverse perm, Permutation.inverse perm)+++data LevelCachePrime sig y =+ LevelCachePrime (Permutation.T, Permutation.T) (sig y)+ deriving (Show)++levelCachePrime ::+ (Element y, SigG.Transform sig y) =>+ LevelPrime -> Cache sig y -> y -> sig y -> LevelCachePrime sig y+levelCachePrime (LevelPrime (perm, rev, inv)) subCache z sig =+ LevelCachePrime (rev, inv)+ ((\zs -> FiltNRG.amplify (recipInteger zs) zs) $+ transformWithCache subCache $+ Permutation.apply perm $+ SigG.takeStateMatch sig $+ SigS.iterate (z*) z)++{- |+Rader's algorithm for prime length signals.+-}+transformPrime ::+ (Element y, SigG.Transform sig y) =>+ LevelCachePrime sig y -> (Cache sig y, Cache sig y) -> sig y -> sig y+transformPrime (LevelCachePrime (rev, inv) zs) subCaches =+ SigG.switchL (error "transformPrime: empty signal") $+ \x0 rest ->+ SigG.cons (SigG.foldL (+) x0 rest) $+ SigG.map (x0+) $+ Permutation.apply inv $+ convolveSpectrumCyclicCache subCaches zs $+ Permutation.apply rev rest++{-+Cyclic.reverse xs = shiftR 1 (reverse xs)+Cyclic.reverse (xs <*> ys) = Cyclic.reverse xs <*> Cyclic.reverse ys+Cyclic.reverse (Cyclic.reverse xs) = xs++We could move the 'Cyclic.reverse' over to the z-vector,+but then we would have to reverse again after convolution.++zs <*> Cyclic.reverse rest+ = Cyclic.reverse (Cyclic.reverse zs <*> rest)+-}++{-+This uses Cyclic.filter instead of Cyclic.convolve.+This is simpler, but Fourier.convolveCyclic is a bit simpler than Fourier.filterCyclic,+since it does not need to reverse an operand.+-}+_transformPrimeAlt ::+ (Ring.C y, SigG.Transform sig y) =>+ LevelPrime -> y -> sig y -> sig y+_transformPrimeAlt (LevelPrime (perm, _, inv)) z =+ SigG.switchL (error "transformPrime: empty signal") $+ \x0 rest ->+ SigG.cons (SigG.foldL (+) x0 rest) $+ SigG.map (x0+) $+ Permutation.apply inv $+ Cyclic.filterNaive+ (Permutation.apply perm rest)+ (Permutation.apply perm (SigG.takeStateMatch rest (SigS.iterate (z*) z)))++++{- |+Filter window stored as spectrum+such that it can be applied efficiently to long signals.+-}+data Window sig y =+ Window Int (Cache sig y, Cache sig y) (sig y)+ deriving (Show)+++window ::+ (Element y, SigG.Transform sig y) =>+ sig y -> Window sig y+window x =+ if CutG.null x+ then Window 0 (CacheIdentity, CacheIdentity) CutG.empty+ else+ let size = CutG.length x+ size2 = 2 * NumberTheory.ceilingPowerOfTwo size+ padded =+ SigG.take size2 $+ CutG.append x $+ let pad = SigG.takeStateMatch x $ SigS.repeat $ addId x+ in CutG.append pad (SigG.append pad pad)+ caches@(cache, _cacheInv) =+ cacheDuplex padded+ in Window+ (size2-size+1)+ caches+ (transformWithCache cache $+ FiltNRG.amplify (recipInteger padded) padded)++{- |+Efficient convolution of a large filter window+with a probably infinite signal.+-}+convolveWithWindow ::+ (Element y, SigG.Transform sig y) =>+ Window sig y -> sig y -> sig y+convolveWithWindow (Window blockSize caches spectrum) b =+ if blockSize==zero+ then CutG.empty+ else+ let windowSize = SigG.length spectrum - blockSize+ in SigS.foldR (FiltNRG.addShiftedSimple blockSize) CutG.empty $+ SigS.map+ (\block ->+ SigG.take (windowSize + SigG.length block) $+ convolveSpectrumCyclicCache caches spectrum $+ flip CutG.append+ {-+ The last block may be shorter than blockSize+ and thus needs more padding.+ -}+ (SigG.takeStateMatch spectrum $ SigS.repeat $ addId b) $+ block) $+ SigG.sliceVertical blockSize b+++{- |+Signal must have equal size and must not be empty.+-}+convolveCyclic ::+ (Element y, SigG.Transform sig y) =>+ sig y -> sig y -> sig y+convolveCyclic x =+ let len = fromIntegral $ SigG.length x+ (z,zInv) =+ directionPrimitiveRootsOfUnity x+ in convolveCyclicCache+ (cacheFromPlan (plan len) z x,+ cacheFromPlan (plan len) zInv x)+ x++convolveCyclicCache ::+ (Element y, SigG.Transform sig y) =>+ (Cache sig y, Cache sig y) -> sig y -> sig y -> sig y+convolveCyclicCache caches x =+ convolveSpectrumCyclicCache caches $+ FiltNRG.amplify (recipInteger x) $ transformWithCache (fst caches) x++{- |+This function does not apply scaling.+That is you have to scale the spectrum by @recip (length x)@+if you want a plain convolution.+-}+convolveSpectrumCyclicCache ::+ (Element y, SigG.Transform sig y) =>+ (Cache sig y, Cache sig y) -> sig y -> sig y -> sig y+convolveSpectrumCyclicCache (cache,cacheInv) x y =+ transformWithCache cacheInv $+ SigG.zipWith (*) x $+ transformWithCache cache y++{-+Test:++let xs = [0,1,0,0,0,0 :: Complex.T Double]; z = fst $ conjugatePrimitiveRootsOfUnity xs in print (transformNaive z xs) >> print (transformCoprime z (2,3) xs)+-}
src/Synthesizer/Generic/Interpolation.hs view
@@ -21,11 +21,8 @@ import qualified Algebra.Module as Module import qualified Algebra.RealField as RealField import qualified Algebra.RealRing as RealRing--- import qualified Algebra.Field as Field--- import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import Algebra.Additive(zero, ) import Data.Maybe (fromMaybe, ) import NumericPrelude.Base
+ src/Synthesizer/Generic/LengthSignal.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE FlexibleInstances #-}+module Synthesizer.Generic.LengthSignal where++import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Generic.Cut as CutG++import qualified Algebra.Additive as Additive++import Data.Monoid (Monoid, mempty, mappend, )+import Data.Tuple.HT (mapSnd, )++import NumericPrelude.Numeric as NP+import NumericPrelude.Base hiding (length, splitAt, )+++data T sig = Cons {length :: Int, body :: sig}+ deriving (Show)++fromSignal :: (CutG.Read sig) => sig -> T sig+fromSignal xs = Cons (CutG.length xs) xs++toSignal :: T sig -> sig+toSignal = body++{- |+Each fmap must preserve the signal length.+-}+instance Functor T where+ fmap f (Cons xl xs) = Cons xl (f xs)++instance (Additive.C a, SigG.Transform sig a) => Additive.C (T (sig a)) where+ zero = mempty+ negate xs = xs{body = SigG.map negate (body xs)}+ (Cons xl xs) + (Cons yl ys) =+ Cons (max xl yl) (SigG.mix xs ys)++instance (Monoid sig) => Monoid (T sig) where+ mempty = Cons zero mempty+ mappend (Cons xl xs) (Cons yl ys) =+ Cons (xl+yl) (mappend xs ys)++splitAt :: (CutG.Transform sig) => Int -> T sig -> (T sig, T sig)+splitAt n (Cons xl xs) =+ let (ys,zs) = SigG.splitAt n xs+ in (Cons (min n xl) ys, Cons (max n xl - n) zs)++{- |+It must hold @delay <= length a@.+-}+{-+It is crucial that 'mix' uses the chunk size structure of the second operand.+This way we avoid unnecessary and even infinite look-ahead.+-}+{-# INLINE addShiftedSimple #-}+addShiftedSimple ::+ (Additive.C a, SigG.Transform sig a) =>+ Int -> T (sig a) -> T (sig a) -> T (sig a)+addShiftedSimple del a b =+ uncurry mappend $+ mapSnd (flip (+) b) $+ splitAt del a
src/Synthesizer/Generic/Loop.hs view
@@ -30,9 +30,7 @@ import qualified Algebra.Transcendental as Trans import qualified Algebra.Module as Module import qualified Algebra.RealField as RealField-import qualified Algebra.RealRing as RealRing-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive+import qualified Algebra.RealRing as RealRing import NumericPrelude.Numeric import NumericPrelude.Base
src/Synthesizer/Generic/Noise.hs view
@@ -13,9 +13,7 @@ import qualified Algebra.Ring as Ring import System.Random (Random, RandomGen, randomR, mkStdGen, )-import qualified System.Random as Rnd -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Generic/Oscillator.hs view
@@ -29,24 +29,10 @@ import Control.Arrow ((>>>), ) -{--import qualified Algebra.RealTranscendental as RealTrans-import qualified Algebra.Module as Module-import qualified Algebra.VectorSpace as VectorSpace--import Algebra.Module((*>))--} 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 Number.NonNegative as NonNeg- import NumericPrelude.Numeric---- import qualified Prelude as P import NumericPrelude.Base
+ src/Synthesizer/Generic/Permutation.hs view
@@ -0,0 +1,151 @@+{- |+Permutations of signals as needed for Fast Fourier transforms.+Most functions are independent of the Signal framework.+We could move them as well to Synthesizer.Basic.+-}+module Synthesizer.Generic.Permutation where++import qualified Synthesizer.Basic.NumberTheory as NumberTheory++import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.State.Signal as SigS++import qualified Data.StorableVector.ST.Strict as SVST+import qualified Data.StorableVector as SV++import qualified Algebra.PrincipalIdealDomain as PID++++type T = SV.Vector Int++apply ::+ (SigG.Transform sig y) =>+ T -> sig y -> sig y+apply p xs =+ SigG.takeStateMatch xs $+ SigS.map (SigG.index xs) $+ SigS.fromStrictStorableSignal p+++size :: T -> Int+size = SV.length+++{- |+> inverse (transposition n m) = transposition m n+-}+transposition ::+ Int -> Int -> T+transposition n m =+ fst $ SV.unfoldrN (n*m)+ (\(i,j,k0) -> Just (i,+ case pred k0 of+ 0 -> let j1 = j+1 in (j1, j1, m)+ k1 -> (i+n, j, k1)))+ (0,0,m)+++{-+In general the inverse of a skewGrid+does not look like even a generalized skewGrid.+E.g. @inverse $ skewGrid 3 4@.+-}+skewGrid ::+ Int -> Int -> T+skewGrid n m =+ let len = n*m+ in fst $ SV.unfoldrN len+ (\(i0,k0) -> Just (i0,+ let k1 = pred k0+ i1 = i0+n+ in if k1==0+ then (mod (i1+m) len, m)+ else (mod i1 len, k1)))+ (0,m)++{- |+> inverse (skewGrid n m) == skewGridInv n m++In general the inverse of a skewGrid+cannot be expressed like skewGrid or skewGridCRT.+E.g. @inverse $ skewGrid 3 4@.+-}+skewGridInv ::+ Int -> Int -> T+skewGridInv n m =+ SV.pack $+ map (\k ->+ let Just (i,j) = PID.diophantine k n m+ in mod i m + mod j n * m) $+ take (n*m) $ iterate (1+) 0++skewGridCRT ::+ Int -> Int -> T+skewGridCRT n m =+ let len = n*m+ (ni,mi) = snd $ PID.extendedGCD n m+ in fst $ SV.unfoldrN len+ (\(i0,k0) -> Just (i0,+ let k1 = pred k0+ i1 = i0+ni*n+ in if k1==0+ then (mod (i1+mi*m) len, m)+ else (mod i1 len, k1)))+ (0,m)++skewGridCRTInv ::+ Int -> Int -> T+skewGridCRTInv n m =+ fst $ SV.packN (n*m) $+ map (\k -> mod k m + mod k n * m) $+ iterate (1+) 0+++{- |+Beware of 0-based indices stored in the result vector.+-}+multiplicative :: Int -> T+multiplicative ni =+ let n = fromIntegral ni+ gen = NumberTheory.multiplicativeGenerator n+ in {-+ Since 'gen' is usually 2 or 3,+ the error should occur really only for huge signals.+ -}+ if gen * n > fromIntegral (maxBound :: Int)+ then error "signal too long for Int indexing"+ else fst $ SV.unfoldrN (ni-1)+ (\x -> Just (x-1, mod (fromInteger gen * x) ni)) 1++{- |+We only need to compute the inverse permutation explicitly,+because not all signal structures support write to arbitrary indices,+thus Generic.Write does not support it.+For strict StorableVector it would be more efficient+to build the vector directly.++It holds:++> inverse . inverse == id+-}+inverse :: T -> T+inverse perm =+ SVST.runSTVector+ (do inv <- SVST.new_ (SV.length perm)+ SigS.sequence_ $+ SigS.zipWith (SVST.write inv)+ (SigS.fromStrictStorableSignal perm)+ (SigS.iterate (1+) 0)+ return inv)++reverse :: T -> T+reverse perm =+ fst $ SV.unfoldrN (SV.length perm)+ (\mn -> Just $+ case mn of+ Nothing -> (SV.head perm, Just $ SV.length perm)+ Just n ->+ let n1 = n-1+ in (SV.index perm n1, Just n1))+ Nothing
src/Synthesizer/Generic/Piece.hs view
@@ -24,10 +24,7 @@ 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 NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Generic/Signal.hs view
@@ -35,13 +35,21 @@ import qualified Synthesizer.Plain.Signal as Sig import qualified Synthesizer.State.Signal as SigS import qualified Synthesizer.Storable.Signal as SigSt-import qualified Data.StorableVector.Lazy as Vector+import qualified Data.StorableVector.Lazy as SVL+import qualified Data.StorableVector as SV import qualified Synthesizer.Plain.Modifier as Modifier -import qualified Algebra.NonNegative as NonNeg+import qualified Algebra.ToInteger as ToInteger+import qualified Algebra.ToRational as ToRational+import qualified Algebra.Absolute as Absolute+import qualified Algebra.RealIntegral as RealIntegral+import qualified Algebra.IntegralDomain as Integral+import qualified Algebra.NonNegative as NonNeg+import qualified Algebra.ZeroTestable as ZeroTestable import qualified Algebra.Module as Module+import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive import qualified Algebra.Monoid as Monoid @@ -59,14 +67,16 @@ import qualified Data.List.Stream as List import Data.Tuple.HT (mapPair, mapFst, ) +import qualified Test.QuickCheck as QC+ -- import NumericPrelude.Numeric import qualified Prelude as P import Prelude- (Bool, Int, Maybe(Just), maybe, snd,- (==), (<), (>), (<=), (>=),+ (Bool, Int, Maybe(Just), maybe, fst, snd,+ (==), (<), (>), (<=), (>=), compare, Ordering(..), flip, uncurry, const, (.), ($), (&&), id, (++), fmap, return, error, show,- Eq, Ord, Show, max, min, )+ Eq, Ord, Show, min, ) class Cut.Read (sig y) => Read sig y where@@ -108,7 +118,10 @@ but we need control over packet size in applications with feedback. -} newtype LazySize = LazySize Int- deriving (Eq, Ord, Show, Additive.C)+ deriving (Eq, Ord, Show,+ Additive.C, Ring.C, ZeroTestable.C,+ ToInteger.C, ToRational.C, Absolute.C,+ RealIntegral.C, Integral.C) instance Monoid.C LazySize where idt = LazySize 0@@ -117,6 +130,12 @@ instance NonNeg.C LazySize where split = NonNeg.splitDefault (\(LazySize n) -> n) LazySize +instance QC.Arbitrary LazySize where+ arbitrary =+ case defaultLazySize of+ LazySize n -> fmap LazySize (QC.choose (1, 2 P.* n))++ {- | This can be used for internal signals that have no observable effect on laziness.@@ -126,7 +145,7 @@ -} defaultLazySize :: LazySize defaultLazySize =- let (Vector.ChunkSize size) = Vector.defaultChunkSize+ let (SVL.ChunkSize size) = SVL.defaultChunkSize in LazySize size {- |@@ -148,65 +167,108 @@ -- instance Storable y => Read SigSt.T y where-instance Storable y => Read Vector.Vector y where+instance Storable y => Read SVL.Vector y where {-# INLINE toList #-}- toList = Vector.unpack+ toList = SVL.unpack {-# INLINE toState #-} toState = SigS.fromStorableSignal {-# INLINE foldL #-}- foldL = Vector.foldl+ foldL = SVL.foldl {-# INLINE foldR #-}- foldR = Vector.foldr+ foldR = SVL.foldr {-# INLINE index #-}- index = Vector.index+ index = SVL.index -instance Storable y => Transform Vector.Vector y where+instance Storable y => Transform SVL.Vector y where {-# INLINE cons #-}- cons = Vector.cons+ cons = SVL.cons {-# INLINE takeWhile #-}- takeWhile = Vector.takeWhile+ takeWhile = SVL.takeWhile {-# INLINE dropWhile #-}- dropWhile = Vector.dropWhile+ dropWhile = SVL.dropWhile {-# INLINE span #-}- span = Vector.span+ span = SVL.span {-# INLINE viewL #-}- viewL = Vector.viewL+ viewL = SVL.viewL {-# INLINE viewR #-}- viewR = Vector.viewR+ viewR = SVL.viewR {-# INLINE map #-}- map = Vector.map+ map = SVL.map {-# INLINE scanL #-}- scanL = Vector.scanl+ scanL = SVL.scanl {-# INLINE crochetL #-}- crochetL = Vector.crochetL+ crochetL = SVL.crochetL {-# INLINE zipWithAppend #-} zipWithAppend = SigSt.zipWithAppend withStorableContext ::- (Vector.ChunkSize -> a) -> (LazySize -> a)+ (SVL.ChunkSize -> a) -> (LazySize -> a) withStorableContext f =- \(LazySize size) -> f (Vector.ChunkSize size)+ \(LazySize size) -> f (SVL.ChunkSize size) -instance Storable y => Write Vector.Vector y where+instance Storable y => Write SVL.Vector y where {-# INLINE fromList #-}- fromList = withStorableContext $ \size -> Vector.pack size+ fromList = withStorableContext $ \size -> SVL.pack size {-# INLINE repeat #-}- repeat = withStorableContext $ \size -> Vector.repeat size+ repeat = withStorableContext $ \size -> SVL.repeat size {-# INLINE replicate #-}- replicate = withStorableContext $ \size -> Vector.replicate size+ replicate = withStorableContext $ \size -> SVL.replicate size {-# INLINE iterate #-}- iterate = withStorableContext $ \size -> Vector.iterate size+ iterate = withStorableContext $ \size -> SVL.iterate size {-# INLINE unfoldR #-}- unfoldR = withStorableContext $ \size -> Vector.unfoldr size+ unfoldR = withStorableContext $ \size -> SVL.unfoldr size {-# INLINE iterateAssociative #-}- iterateAssociative = withStorableContext $ \size op x -> Vector.iterate size (op x) x -- should be optimized+ iterateAssociative = withStorableContext $ \size op x -> SVL.iterate size (op x) x -- should be optimized +instance Storable y => Read SV.Vector y where+ {-# INLINE toList #-}+ toList = SV.unpack+ {-# INLINE toState #-}+ toState = SigS.fromStrictStorableSignal+ {-# INLINE foldL #-}+ foldL = SV.foldl+ {-# INLINE foldR #-}+ foldR = SV.foldr+ {-# INLINE index #-}+ index = SV.index++instance Storable y => Transform SV.Vector y where+ {-# INLINE cons #-}+ cons = SV.cons+ {-# INLINE takeWhile #-}+ takeWhile = SV.takeWhile+ {-# INLINE dropWhile #-}+ dropWhile = SV.dropWhile+ {-# INLINE span #-}+ span = SV.span++ {-# INLINE viewL #-}+ viewL = SV.viewL+ {-# INLINE viewR #-}+ viewR = SV.viewR++ {-# INLINE map #-}+ map = SV.map+ {-# INLINE scanL #-}+ scanL = SV.scanl+ {-# INLINE crochetL #-}+ crochetL f acc =+ fst . SVL.crochetLChunk f acc+ -- fst . SV.crochetContL f acc+ {-# INLINE zipWithAppend #-}+ zipWithAppend f xs ys =+ case compare (SV.length xs) (SV.length ys) of+ EQ -> SV.zipWith f xs ys+ LT -> SV.append (SV.zipWith f xs ys) (SV.drop (SV.length xs) ys)+ GT -> SV.append (SV.zipWith f xs ys) (SV.drop (SV.length ys) xs)++ instance Read [] y where {-# INLINE toList #-} toList = id@@ -478,6 +540,10 @@ SigS.runSwitchL . toState +{-# INLINE singleton #-}+singleton :: (Transform sig y) => y -> sig y+singleton x = cons x mempty+ {-# INLINE mix #-} mix :: (Additive.C y, Transform sig y) => sig y -> sig y -> sig y@@ -486,13 +552,13 @@ {-# INLINE zipWith #-} zipWith :: (Read sig a, Transform sig b) => (a -> b -> b) -> (sig a -> sig b -> sig b)-zipWith h =- flip runViewL (\next ->- crochetL- (\x0 a0 ->- do (y0,a1) <- next a0- Just (h y0 x0, a1)))+zipWith h = zipWithState h . toState +{-# INLINE zipWith3 #-}+zipWith3 :: (Read sig a, Read sig b, Transform sig c) =>+ (a -> b -> c -> c) -> (sig a -> sig b -> sig c -> sig c)+zipWith3 h as bs = zipWithState3 h (toState as) (toState bs)+ {-# INLINE zipWithState #-} zipWithState :: (Transform sig b) => (a -> b -> b) -> SigS.T a -> sig b -> sig b@@ -508,6 +574,18 @@ zipWithState3 h a b = zipWithState ($) (SigS.zipWith h a b) +{- |+@takeStateMatch len xs@+keeps a prefix of @xs@ of the same length and block structure as @len@+and stores it in the same type of container as @len@.+-}+{-# INLINE takeStateMatch #-}+takeStateMatch :: (Transform sig a) =>+ sig a -> SigS.T a -> sig a+takeStateMatch x y =+ zipWithState const y x++ {-# INLINE delay #-} delay :: (Write sig y) => LazySize -> y -> Int -> sig y -> sig y@@ -534,7 +612,7 @@ It's absolutely necessary that this function preserves the chunk structure and that it does not look a chunk ahead. That's guaranteed for processes that do not look ahead at all,- like 'Vector.map', 'Vector.crochetL' and+ like 'SVL.map', 'SVL.crochetL' and all of type @Causal.Process@. -} -> sig y -- ^ input -> sig y -- ^ output has the same length as the input@@ -547,6 +625,17 @@ {-# INLINE sum #-} sum :: (Additive.C a, Read sig a) => sig a -> a sum = foldL (Additive.+) Additive.zero++{-# INLINE sum1 #-}+sum1 :: (Additive.C a, Read sig a) => sig a -> a+sum1 = SigS.foldL1 (Additive.+) . toState+{-+sum1 :: (Additive.C a, Transform sig a) => sig a -> a+sum1 =+ switchL+ (error "Generic.Signal.sum1: signal must be non-empty in order to avoid to use a non-existing zero")+ (foldL (Additive.+))+-} {-# INLINE monoidConcatMap #-} monoidConcatMap :: (Read sig a, Monoid m) => (a -> m) -> sig a -> m
src/Synthesizer/Generic/Signal2.hs view
@@ -36,8 +36,8 @@ import Data.Tuple.HT (fst3, snd3, thd3, ) import Prelude (Integral,- Bool, Int, Maybe(Just), maybe, fst, snd,- flip, ($), (.),+ Maybe(Just), maybe, fst, snd,+ flip, const, ($), (.), return, ) @@ -205,3 +205,14 @@ (a -> b -> c -> d) -> (SigS.T a -> SigS.T b -> sig c -> sig d) zipWithState3 h a b = zipWithState ($) (SigS.zipWith h a b)++{- |+@takeStateMatch len xs@+keeps a prefix of @xs@ of the same length and block structure as @len@+and stores it in the same type of container as @len@.+-}+{-# INLINE takeStateMatch #-}+takeStateMatch :: (Transform sig a b) =>+ sig a -> SigS.T b -> sig b+takeStateMatch x y =+ zipWithState const y x
src/Synthesizer/Interpolation/Class.hs view
@@ -10,7 +10,6 @@ import qualified Algebra.Module as Module import qualified Algebra.PrincipalIdealDomain as PID import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import qualified Sound.Frame.NumericPrelude.Stereo as Stereo import qualified Number.Ratio as Ratio
src/Synthesizer/Interpolation/Custom.hs view
@@ -24,8 +24,6 @@ ) import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import Synthesizer.Interpolation.Class ((+.*), )
src/Synthesizer/Interpolation/Module.hs view
@@ -24,12 +24,7 @@ ) import qualified Algebra.Module as Module--- 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 Algebra.Module((*>)) import Control.Applicative (liftA2, ) import Synthesizer.ApplicativeUtility (liftA4, )
src/Synthesizer/Plain/Analysis.hs view
@@ -25,12 +25,9 @@ import qualified Data.IntMap as IntMap --- import Algebra.Module((*>))- import Data.Array (accumArray) import Data.List (foldl', ) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric @@ -323,10 +320,9 @@ chirpTransform :: Ring.C y => y -> Sig.T y -> Sig.T y chirpTransform z xs =- let powers = Ctrl.curveMultiscaleNeutral (*) z one- powerPowers =- map (\zn -> Ctrl.curveMultiscaleNeutral (*) zn one) powers- in map (scalarProduct xs) powerPowers+ map (scalarProduct xs) $+ map (\zn -> Ctrl.curveMultiscaleNeutral (*) zn one) $+ Ctrl.curveMultiscaleNeutral (*) z one binarySign ::@@ -335,11 +331,33 @@ map (binaryLevelFromBool . (zero <=)) {- |-The output type could be different from the input type-but then we would need a conversion from output to input for feedback.+A kind of discretization for signals with sample values between -1 and 1.+If you smooth the resulting signal+(after you transformed with 'map binaryLevelToNumber'),+you should obtain an approximation to the input signal. -} deltaSigmaModulation :: RealRing.C y => Sig.T y -> Sig.T BinaryLevel deltaSigmaModulation x =+ let y = binarySign (Integration.run (x - (zero : map binaryLevelToNumber y)))+ in y+{- let y = binarySign (Integration.runInit zero (x - map binaryLevelToNumber y))+ in y+-}++{- |+A kind of discretization for signals with sample values between 0 and a threshold.+We accumulate input values and emit a threshold value+whenever the accumulator exceeds the threshold.+This is intended for generating clicks from input noise.++See also 'deltaSigmaModulation'.+-}+deltaSigmaModulationPositive ::+ RealRing.C y => y -> Sig.T y -> Sig.T y+deltaSigmaModulationPositive threshold x =+ let y =+ map (\xi -> if xi>=threshold then threshold else zero) $+ Integration.run (x - (zero:y)) in y
src/Synthesizer/Plain/Builder.hs view
@@ -10,8 +10,7 @@ import qualified Algebra.ToInteger as ToInteger import qualified Algebra.RealField as RealField -import qualified Prelude as P98-+import Prelude () import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Control.hs view
@@ -14,14 +14,10 @@ import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import Algebra.Module((*>))--import Number.Complex (cis,real)--- import qualified Number.Complex as Complex+import Number.Complex (cis,real, ) import Data.List (zipWith4, tails, ) import Data.List.HT (iterateAssociative, ) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Effect.hs view
@@ -15,16 +15,18 @@ import Synthesizer.Plain.Effect.Glass(glass) import qualified Synthesizer.Plain.File as File+import qualified Control.Monad.Exception.Synchronous as Exc import System.Exit(ExitCode) import System.Cmd(rawSystem) main :: IO ExitCode main = let rate = 44100- in do {- File.writeMono "test" rate+ in Exc.toExitCodeT $+ do {- File.writeMono "test" rate (take (round (3*rate)) (soundD rate)) -}- File.renderMonoToInt16 "test.aiff" rate soundE- rawSystem "play" ["test.aiff"]+ Exc.fromExitCodeT $ File.renderMonoToInt16 "test.aiff" rate soundE+ Exc.fromExitCodeT $ rawSystem "play" ["test.aiff"] soundE, soundB, soundA,
src/Synthesizer/Plain/Effect/Fly.hs view
@@ -1,15 +1,17 @@ {-# LANGUAGE NoImplicitPrelude #-} module Synthesizer.Plain.Effect.Fly where +import qualified Synthesizer.Causal.Spatial as Spatial+import qualified Synthesizer.Causal.Process as Causal+ import qualified Synthesizer.Plain.Oscillator as Osci import qualified Synthesizer.Plain.Filter.NonRecursive as FiltNR import qualified Synthesizer.Plain.Interpolation as Interpolation-import qualified Synthesizer.Plain.Miscellaneous as Syn import qualified Synthesizer.Plain.File as File import System.Exit(ExitCode) -import System.Random+import System.Random (randomRs, mkStdGen, ) import qualified Algebra.NormedSpace.Euclidean as Euc @@ -18,7 +20,7 @@ {-- ghc -O -fvia-C -fglasgow-exts -fallow-undecidable-instances --make Fly.hs && echo start && time a.out+ ghc -O -fvia-C --make Fly.hs && echo start && time a.out -} main :: IO ExitCode@@ -29,7 +31,7 @@ sampleRate :: Double sampleRate = 44100 -{-| stereo sound of a humming fly -}+{- | stereo sound of a humming fly -} fly :: [(Double,Double)] fly = let pinkNoise seed freq range =@@ -49,11 +51,12 @@ (flyCoord 654891) channel ear =- let (phase,volumes) = Syn.receive3Dsound 1 0.1 ear trajectory+ let (phase,volumes) =+ unzip $ Causal.apply (Spatial.receive3Dsound 1 0.1 ear) trajectory -- (*sampleRate) in 'speed' and -- (/sampleRate) in 'freqs' neutralizes- speeds = map (\v -> 250/sampleRate+2*(Euc.norm v))- (zipWith subtract (tail trajectory) trajectory)+ speeds = map (\v -> 250/sampleRate + 2 * Euc.norm v)+ (FiltNR.differentiate trajectory) freqs = zipWith (+) speeds (FiltNR.differentiate phase) sound = Osci.freqModSaw 0 freqs in zipWith (*) (map (10*) volumes) sound
src/Synthesizer/Plain/Effect/Glass.hs view
@@ -13,11 +13,12 @@ import qualified Algebra.Transcendental as Trans import qualified Algebra.RealField as RealField-import qualified Algebra.Additive as Additive import qualified Algebra.Module as Module import System.Random(randomRs, mkStdGen) +import qualified Data.List.HT as ListHT+ import NumericPrelude.Base import NumericPrelude.Numeric as NP @@ -63,8 +64,4 @@ in diffs (NonNeg.fromNumber 0) timeDiffs :: [Bool] -> [NonNeg.Int]-timeDiffs = map (NonNeg.fromNumber . length) . segmentBefore id--segmentBefore :: (a -> Bool) -> [a] -> [[a]]-segmentBefore p =- foldr (\ x ~(y:ys) -> (if p x then ([]:) else id) ((x:y):ys)) [[]]+timeDiffs = map (NonNeg.fromNumber . length) . ListHT.segmentBefore id
src/Synthesizer/Plain/File.hs view
@@ -1,5 +1,22 @@ {-# LANGUAGE NoImplicitPrelude #-}-module Synthesizer.Plain.File where+module Synthesizer.Plain.File (+ render,+ renderToInt16,+ renderMonoToInt16,+ renderStereoToInt16,+ write,+ writeToInt16,+ writeMonoToInt16,+ writeStereoToInt16,+ writeRaw,+ writeRawCompressed,+ rawToAIFF,+ compress,+ readAIFFMono,+ readMonoFromInt16,+ -- will no longer be exported+ getInt16List,+ ) where import qualified Sound.Sox.Convert as Convert import qualified Sound.Sox.Frame as Frame@@ -18,6 +35,8 @@ import Foreign.Storable (Storable, ) import Data.Int (Int16, ) +import qualified Control.Monad.Exception.Synchronous as Exc+import Control.Monad.Trans.Class (lift, ) import System.Cmd (rawSystem, ) import System.Exit (ExitCode, ) import Control.Monad (liftM2, )@@ -113,8 +132,9 @@ writeRawCompressed :: (RealRing.C a, Frame.C v, Storable v) => SoxOpt.T -> FilePath -> a -> [v] -> IO ExitCode writeRawCompressed opts fileName sampleRate signal =- do writeRaw opts fileName sampleRate signal- compress fileName+ Exc.toExitCodeT $+ do Exc.fromExitCodeT $ writeRaw opts fileName sampleRate signal+ Exc.fromExitCodeT $ compress fileName {-# DEPRECATED rawToAIFF "If you want to generate AIFF, then just write to files with .aiff filename extension. If you want to convert files to AIFF, use Sound.Sox.Convert." #-}@@ -133,9 +153,9 @@ SoxOpt.none fileNameAIFF compress :: FilePath -> IO ExitCode-compress fileName =- do rawSystem "oggenc" ["--quality", "5", fileName]- rawSystem "lame"+compress fileName = Exc.toExitCodeT $+ do Exc.fromExitCodeT $ rawSystem "oggenc" ["--quality", "5", fileName]+ Exc.fromExitCodeT $ rawSystem "lame" ["-h", fileName, FilePath.replaceExtension fileName "mp3"] @@ -155,10 +175,12 @@ -} readAIFFMono :: (Field.C a) => FilePath -> IO [a] readAIFFMono file =- do --putStrLn ("sox "++file++" "++tmp)- let tmp = FilePath.replaceExtension file "sw"- Convert.simple SoxOpt.none file SoxOpt.none tmp- fmap (map BinSmp.int16ToCanonical) (FileL.readInt16StreamStrict tmp)+ let tmp = FilePath.replaceExtension file "s16"+ in Exc.resolveT (const $ return []) $ do+ -- lift $ putStrLn ("sox "++file++" "++tmp)+ Exc.fromExitCodeT $ Convert.simple SoxOpt.none file SoxOpt.none tmp+ fmap (map BinSmp.int16ToCanonical) $+ lift $ FileL.readInt16StreamStrict tmp {- |@@ -167,12 +189,14 @@ readMonoFromInt16 :: (Field.C a) => FilePath -> IO [a] readMonoFromInt16 fileName = Read.open SoxOpt.none fileName >>=- Read.withHandle1 (fmap (Get.runGet getInt16List) . B.hGetContents) >>=+ Read.withHandle1 (fmap (Get.runGet getInt16ListPrivate) . B.hGetContents) >>= return . map BinSmp.int16ToCanonical -getInt16List :: Get.Get [Int16]-getInt16List =+{-# DEPRECATED getInt16List "This function will no longer be exported" #-}+getInt16List, getInt16ListPrivate :: Get.Get [Int16]+getInt16List = getInt16ListPrivate+getInt16ListPrivate = do b <- Get.isEmpty if b then return []- else liftM2 (:) (fmap fromIntegral Get.getWord16host) getInt16List+ else liftM2 (:) (fmap fromIntegral Get.getWord16host) getInt16ListPrivate
src/Synthesizer/Plain/Filter/Delay.hs view
@@ -9,7 +9,6 @@ import qualified Algebra.Module as Module import qualified Algebra.RealField as RealField-import qualified Algebra.Additive as Additive import qualified Synthesizer.Plain.Interpolation as Interpolation @@ -17,7 +16,6 @@ import qualified Synthesizer.Plain.Filter.Delay.List as DelayList import qualified Synthesizer.Plain.Filter.Delay.Block as DelayBlock -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/Delay/Block.hs view
@@ -18,7 +18,6 @@ import Test.QuickCheck ((==>), Property) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/Delay/List.hs view
@@ -8,7 +8,6 @@ import Data.List(tails) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/Delay/ST.hs view
@@ -13,7 +13,6 @@ import Control.Monad.ST.Lazy(runST,strictToLazyST,ST) import Data.Array.ST -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/LinearPredictive.hs view
@@ -1,8 +1,6 @@ module Synthesizer.Plain.Filter.LinearPredictive where import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import Synthesizer.Plain.Analysis (scalarProduct) import qualified Data.List.Match as ListMatch
src/Synthesizer/Plain/Filter/NonRecursive.hs view
@@ -19,7 +19,7 @@ import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import Algebra.Module(linearComb, (*>))+import Algebra.Module(linearComb, ) import Data.Function.HT (nest, ) import Data.Tuple.HT (mapPair, swap, )
src/Synthesizer/Plain/Filter/Recursive.hs view
@@ -12,15 +12,11 @@ module Synthesizer.Plain.Filter.Recursive where import qualified Algebra.Module as Module--- import qualified Algebra.Transcendental as Trans--- import qualified Algebra.Field as Field--- import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive import Algebra.Additive((+), (-), negate, ) import Algebra.Module((*>)) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/Recursive/Allpass.hs view
@@ -28,9 +28,6 @@ import qualified Algebra.Transcendental as Trans import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import Algebra.Module((*>)) import qualified Number.Complex as Complex import Data.Tuple.HT (mapSnd, )
src/Synthesizer/Plain/Filter/Recursive/AllpassPoly.hs view
@@ -18,10 +18,6 @@ import qualified Algebra.RealTranscendental as RealTrans import qualified Algebra.Transcendental as Trans import qualified Algebra.Field as Field-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import Algebra.Module((*>)) import Number.Complex (cis,(+:),real,imag) import qualified Number.Complex as Complex
src/Synthesizer/Plain/Filter/Recursive/Butterworth.hs view
@@ -24,14 +24,11 @@ import qualified Algebra.Module as Module import qualified Algebra.Transcendental as Trans-import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import qualified Data.StorableVector as SV import Foreign.Storable (Storable) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/Recursive/Chebyshev.hs view
@@ -22,24 +22,16 @@ import qualified Synthesizer.Causal.Process as Causal import Control.Arrow ((>>>), (^>>), (&&&), ) --- import qualified Algebra.VectorSpace as VectorSpace import qualified Algebra.Module as Module import qualified Algebra.Transcendental as Trans-import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive -import Algebra.Module((*>))- import Number.Complex (real, imag, cis, ) import qualified Number.Complex as Complex --- import Control.Monad.Trans.State (State(..), evalState)- import qualified Data.StorableVector as SV import Foreign.Storable (Storable) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric @@ -272,6 +264,14 @@ Filt2.adjustPassband kind (flip (partialParameterA order ratio) c) freq) $ circleVec)++{-# INLINE canonicalizeParameterA #-}+canonicalizeParameterA ::+ (Ring.C a, Storable a) =>+ ParameterA a -> Cascade.Parameter a+canonicalizeParameterA (amp, Cascade.Parameter p) =+ Cascade.Parameter+ (SV.switchL SV.empty (\h -> SV.cons (Filt2.amplify amp h)) p) type ParameterB a = Cascade.Parameter a
src/Synthesizer/Plain/Filter/Recursive/Comb.hs view
@@ -21,13 +21,9 @@ import qualified Synthesizer.Plain.Control as Ctrl 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 Algebra.Module((*>))--import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/Recursive/FirstOrder.hs view
@@ -2,7 +2,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {- |-Copyright : (c) Henning Thielemann 2008+Copyright : (c) Henning Thielemann 2008-2011 License : GPL Maintainer : synthesizer@henning-thielemann.de@@ -211,20 +211,26 @@ {-# INLINE step #-}-step :: (Ring.C a, Module.C a v) =>+step :: (Module.C a v) => Parameter a -> v -> State v (Result v) step c x = fmap (\lp -> Result (x-lp) lp) (lowpassStep c x) {-# INLINE modifierInit #-}-modifierInit :: (Ring.C a, Module.C a v) =>- Modifier.Initialized v v (Parameter a) v v+modifierInit :: (Module.C a v) =>+ Modifier.Initialized v v (Parameter a) v (Result v) modifierInit =- Modifier.Initialized id lowpassStep+ Modifier.Initialized id step {-# INLINE modifier #-}-modifier :: (Ring.C a, Module.C a v) =>- Modifier.Simple v (Parameter a) v v+modifier :: (Module.C a v) =>+ Modifier.Simple v (Parameter a) v (Result v) modifier = Sig.modifierInitialize modifierInit zero +{-# INLINE causal #-}+causal ::+ (Module.C a v) =>+ Causal.T (Parameter a, v) (Result v)+causal =+ Causal.fromSimpleModifier modifier
src/Synthesizer/Plain/Filter/Recursive/FirstOrderComplex.hs view
@@ -38,15 +38,10 @@ import qualified Algebra.Module as Module import qualified Algebra.Transcendental as Trans import qualified Algebra.Algebraic as Algebraic-import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive --- import Algebra.Module((*>))- import Control.Monad.Trans.State (State, state, ) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/Recursive/Hilbert.hs view
@@ -39,9 +39,6 @@ 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 Algebra.Module((*>)) import qualified Number.Complex as Complex import Number.Complex ((+:), )
src/Synthesizer/Plain/Filter/Recursive/Moog.hs view
@@ -28,11 +28,7 @@ import qualified Algebra.Module as Module import qualified Algebra.Transcendental as Trans-import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive--import Algebra.Module((*>)) import Data.Function.HT (nest, )
src/Synthesizer/Plain/Filter/Recursive/SecondOrder.hs view
@@ -29,14 +29,10 @@ import qualified Synthesizer.Causal.Process as Causal --- import qualified Algebra.VectorSpace as VectorSpace import qualified Algebra.Module as Module--- import qualified Algebra.Transcendental as Trans import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive--import Algebra.Module((*>)) import Data.List (zipWith6)
src/Synthesizer/Plain/Filter/Recursive/SecondOrderCascade.hs view
@@ -27,21 +27,14 @@ import qualified Synthesizer.Causal.Process as Causal --- import qualified Algebra.VectorSpace as VectorSpace import qualified Algebra.Module as Module--- import qualified Algebra.Transcendental as Trans--- import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring--- import qualified Algebra.Additive as Additive --- import Algebra.Module((*>))- import qualified Control.Monad.Trans.State as MS import qualified Data.StorableVector as SV import Foreign.Storable (Storable(..)) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Filter/Recursive/Universal.hs view
@@ -31,7 +31,6 @@ import qualified Algebra.Module as Module import qualified Algebra.Transcendental as Trans-import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive
src/Synthesizer/Plain/IO.hs view
@@ -23,8 +23,6 @@ import qualified Data.ByteString.Lazy as B import qualified Data.Binary.Builder as Builder -import qualified Algebra.Ring as Ring- import Data.Char (ord, ) import qualified Prelude as P98
src/Synthesizer/Plain/Interpolation.hs view
@@ -33,7 +33,6 @@ import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import Algebra.Additive(zero) import Data.Maybe (fromMaybe) import qualified Data.List.HT as ListHT
src/Synthesizer/Plain/Miscellaneous.hs view
@@ -1,25 +1,26 @@ {-# LANGUAGE NoImplicitPrelude #-}-module Synthesizer.Plain.Miscellaneous where+module Synthesizer.Plain.Miscellaneous+ {-# DEPRECATED "Use Synthesizer.Causal.Spatial instead" #-} where +import qualified Synthesizer.Causal.Spatial as Spatial+import qualified Synthesizer.Causal.Process as Causal+ import qualified Algebra.NormedSpace.Euclidean as Euc import qualified Algebra.Field as Field--- import qualified Algebra.Ring as Ring--- import qualified Algebra.Additive as Additive -import qualified Prelude as P import NumericPrelude.Base-import NumericPrelude.Numeric+-- import NumericPrelude.Numeric {- * Spatial effects -} -{-| simulate an moving sounding object- convert the way of the object through 3D space- into a delay and attenuation information,- sonicDelay is the reciprocal of the sonic velocity -}+{-|+simulate an moving sounding object++convert the way of the object through 3D space+into a delay and attenuation information,+sonicDelay is the reciprocal of the sonic velocity+-} receive3Dsound :: (Field.C a, Euc.C a v) => a -> a -> v -> [v] -> ([a],[a])-receive3Dsound att sonicDelay ear way =- let dists = map (Euc.norm) (map (subtract ear) way)- phase = map (sonicDelay*) dists- volumes = map (\x -> 1/(att+x)^2) dists- in (phase, volumes)+receive3Dsound att sonicDelay ear =+ unzip . Causal.apply (Spatial.receive3Dsound att sonicDelay ear)
src/Synthesizer/Plain/Noise.hs view
@@ -11,7 +11,6 @@ import Data.List.HT (sliceVertical, ) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Plain/Oscillator.hs view
@@ -23,26 +23,13 @@ import Synthesizer.Plain.ToneModulation (freqsToPhases, ) -{--import qualified Algebra.RealTranscendental as RealTrans-import qualified Algebra.Module as Module-import qualified Algebra.VectorSpace as VectorSpace--import Algebra.Module((*>))--} import qualified Algebra.Transcendental as Trans import qualified Algebra.RealField as RealField import qualified Algebra.RealRing as RealRing-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive --- import qualified Number.NonNegative as NonNeg- import Data.Tuple.HT (mapFst, mapSnd, ) import NumericPrelude.Numeric---- import qualified Prelude as P import NumericPrelude.Base
src/Synthesizer/Plain/Signal.hs view
@@ -1,7 +1,7 @@ {-# OPTIONS_GHC -fglasgow-exts #-} {- glasgow-exts are for the rules -} {- |-Copyright : (c) Henning Thielemann 2008+Copyright : (c) Henning Thielemann 2008-2011 License : GPL Maintainer : synthesizer@henning-thielemann.de@@ -15,6 +15,7 @@ import qualified Synthesizer.Plain.Modifier as Modifier import qualified Data.List.Match as ListMatch+import qualified Data.List.HT as ListHT import qualified Data.List as List import Data.Tuple.HT (forcePair, mapFst, mapSnd, )@@ -146,8 +147,9 @@ dropMarginRem :: Int -> Int -> T a -> (Int, T a) dropMarginRem n m = head .- dropMargin n m .- zipWithTails (,) (iterate pred m)+ dropMargin (1+n) m .+ zip (iterate (max 0 . pred) m) .+ ListHT.tails dropMargin :: Int -> Int -> T a -> T a dropMargin n m xs =@@ -170,7 +172,7 @@ zipWithTails :: (y0 -> T y1 -> y2) -> T y0 -> T y1 -> T y2 zipWithTails f xs =- zipWith f xs . init . List.tails+ zipWith f xs . init . ListHT.tails zipWithRest :: (y0 -> y0 -> y1) ->
src/Synthesizer/Plain/ToneModulation.hs view
@@ -54,12 +54,9 @@ import qualified Synthesizer.Plain.Signal as Sig import qualified Synthesizer.Plain.Interpolation as Interpolation import Synthesizer.Interpolation (Margin, )--- import qualified Data.Array as Array import Data.Array (Array, (!), listArray, ) --- import qualified Algebra.Transcendental as Trans import qualified Algebra.RealField as RealField-import qualified Algebra.Field as Field import qualified Algebra.RealRing as RealRing import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive
src/Synthesizer/Plain/Wave.hs view
@@ -10,11 +10,7 @@ import qualified Synthesizer.Plain.Signal as Sig import Data.Array ((!), listArray) --- import qualified Synthesizer.Basic.Phase as Phase- import qualified Algebra.RealField as RealField-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import NumericPrelude.Numeric
src/Synthesizer/State/Analysis.hs view
@@ -20,16 +20,11 @@ import qualified Algebra.NormedSpace.Euclidean as NormedEuc import qualified Algebra.NormedSpace.Sum as NormedSum -import qualified Data.Array as Array- import qualified Data.IntMap as IntMap---- import Algebra.Module((*>))+import qualified Data.Array as Array import Data.Array (accumArray)--- import Data.List (foldl', ) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric @@ -370,7 +365,6 @@ chirpTransform :: Ring.C y => y -> Sig.T y -> Sig.T y chirpTransform z xs =- let powers = Ctrl.curveMultiscaleNeutral (*) z one- powerPowers =- Sig.map (\zn -> Ctrl.curveMultiscaleNeutral (*) zn one) powers- in Sig.map (scalarProduct xs) powerPowers+ Sig.map (scalarProduct xs) $+ Sig.map (\zn -> Ctrl.curveMultiscaleNeutral (*) zn one) $+ Ctrl.curveMultiscaleNeutral (*) z one
src/Synthesizer/State/Control.hs view
@@ -24,14 +24,8 @@ import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import Algebra.Module((*>))---- import Number.Complex (cis,real)--- import qualified Number.Complex as Complex- import Data.Ix (Ix, ) -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/State/Cut.hs view
@@ -28,7 +28,7 @@ import qualified Algebra.Additive as Additive import qualified Data.Array as Array-import Data.Array (Array, Ix, (!), elems, )+import Data.Array (Array, Ix, (!), ) import Control.Applicative (Applicative, ) import Data.Traversable (sequenceA, )
src/Synthesizer/State/Displacement.hs view
@@ -3,13 +3,10 @@ import qualified Synthesizer.State.Signal as Sig --- import qualified Algebra.Module as Module import qualified Algebra.Transcendental as Trans--- import qualified Algebra.Field as Field import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/State/Filter/NonRecursive.hs view
@@ -21,8 +21,6 @@ import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive -import Algebra.Module( {- linearComb, -} (*>))- import Data.Function.HT (nest, ) import Data.Tuple.HT (mapFst, )
src/Synthesizer/State/Filter/Recursive/Comb.hs view
@@ -20,13 +20,9 @@ import qualified Synthesizer.State.Filter.Delay as Delay 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 Algebra.Module((*>))--import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/State/Interpolation.hs view
@@ -1,17 +1,12 @@ {-# LANGUAGE NoImplicitPrelude #-} module Synthesizer.State.Interpolation where -import qualified Synthesizer.Interpolation as Interpolation import Synthesizer.Interpolation (T, offset, number, func, ) import qualified Synthesizer.State.Signal as Sig --- import qualified Algebra.Module as Module--- import qualified Algebra.Field as Field import qualified Algebra.RealRing as RealRing-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import Data.Maybe (fromMaybe)
src/Synthesizer/State/Noise.hs view
@@ -10,7 +10,6 @@ import System.Random (Random, RandomGen, randomR, mkStdGen, ) import qualified System.Random as Rnd -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/State/NoiseCustom.hs view
@@ -16,7 +16,6 @@ import System.Random (Random, RandomGen, ) import qualified System.Random as Rnd -import qualified Prelude as P import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/State/Signal.hs view
@@ -81,7 +81,7 @@ format = showsPrec instance Functor T where- fmap = map+ fmap g (Cons f s) = Cons (fmap g f) s instance App.Applicative T where pure = singleton@@ -157,6 +157,13 @@ generate PtrSt.viewL . PtrSt.cons +{-# INLINE fromStrictStorableSignal #-}+fromStrictStorableSignal ::+ (Storable a) =>+ V.Vector a -> T a+fromStrictStorableSignal xs =+ map (V.index xs) $ take (V.length xs) $ iterate succ zero+ {-# INLINE toStorableSignal #-} toStorableSignal :: (Storable a) =>@@ -233,7 +240,8 @@ {-# INLINE map #-} map :: (a -> b) -> (T a -> T b)-map f = crochetL (\x _ -> Just (f x, ())) ()+map = fmap+-- map f = crochetL (\x _ -> Just (f x, ())) () {- |@@ -266,7 +274,9 @@ {-# INLINE take #-} take :: Int -> T a -> T a-take = crochetL (\x n -> toMaybe (n>zero) (x, pred n))+take n =+ map snd . takeWhile ((>0) . fst) . zip (iterate pred n)+ -- crochetL (\x n -> toMaybe (n>zero) (x, pred n)) {-# INLINE takeWhile #-} takeWhile :: (a -> Bool) -> T a -> T a@@ -340,6 +350,13 @@ foldL :: (acc -> x -> acc) -> acc -> T x -> acc foldL f = foldL' (flip f) +{-# INLINE foldL1 #-}+foldL1 :: (x -> x -> x) -> T x -> x+foldL1 f =+ switchL+ (error "State.Signal.foldL1: empty signal")+ (foldL f)+ {-# INLINE length #-} length :: T a -> Int length = foldL' (const succ) zero@@ -486,8 +503,8 @@ dropMarginRem :: Int -> Int -> T a -> (Int, T a) dropMarginRem n m = switchL (error $ "StateSignal.dropMaringRem: length xs < " ++ show n) const .- dropMargin n m .- zipWithTails (,) (iterate pred m)+ dropMargin (succ n) m .+ zipWithTails1 (,) (iterate (max 0 . pred) m) {-# INLINE dropMargin #-} dropMargin :: Int -> Int -> T a -> T a@@ -607,9 +624,9 @@ append :: T a -> T a -> T a append xs ys = generate- (\(b,xs0) ->+ (\(b,xys) -> mplus- (fmap (mapSnd ((,) b)) $ viewL xs0)+ (fmap (mapSnd ((,) b)) $ viewL xys) (if b then Nothing else fmap (mapSnd ((,) True)) $ viewL ys))@@ -781,7 +798,7 @@ return (f xs, ys))) -} --- only non-empty suffixes are processed+-- | only non-empty suffixes are processed {-# INLINE zipWithTails #-} zipWithTails :: (y0 -> T y1 -> y2) -> T y0 -> T y1 -> T y2@@ -801,6 +818,26 @@ (xs2,ys2))) -} +-- | in contrast to 'zipWithTails' it also generates the empty suffix (once)+{-# INLINE zipWithTails1 #-}+zipWithTails1 ::+ (y0 -> T y1 -> y2) -> T y0 -> T y1 -> T y2+zipWithTails1 f xs ys =+ generate (\(xs0,ys0) ->+ do (x,xs1) <- viewL xs0+ ys1 <- ys0+ return (f x ys1, (xs1, fmap snd $ viewL ys1)))+ (xs, Just ys)++-- | in contrast to 'zipWithTails' it appends infinitely many empty suffixes+{-# INLINE zipWithTailsInf #-}+zipWithTailsInf ::+ (y0 -> T y1 -> y2) -> T y0 -> T y1 -> T y2+zipWithTailsInf f =+ curry $ generate (\(xs0,ys0) ->+ do (x,xs) <- viewL xs0+ return (f x ys0, (xs, switchL empty (flip const) ys0)))+ {- This can hardly be implemented in an efficient way. But this means, we cannot implement the Generic.Transform class.@@ -912,3 +949,17 @@ fmap (\b -> (b, (Nothing, s0))) carry `mplus` fmap (\((a,b),s1) -> (a, (Just b, s1))) (next s0)) (Nothing,t))++interleave, interleaveAlt ::+ T y -> T y -> T y+interleave xs ys =+ runViewL xs (\nextX sx ->+ runViewL ys (\nextY sy ->+ unfoldR+ (\(select,(sx0,sy0)) ->+ case select of+ False -> fmap (mapSnd (\sx1 -> (True, (sx1,sy0)))) $ nextX sx0+ True -> fmap (mapSnd (\sy1 -> (False, (sx0,sy1)))) $ nextY sy0)+ (False, (sx,sy))))++interleaveAlt xs ys = flattenPairs $ zip xs ys
src/Synthesizer/Storable/Cut.hs view
@@ -12,16 +12,13 @@ import qualified Data.EventList.Relative.TimeMixed as EventListTM import qualified Data.EventList.Absolute.TimeBody as AbsEventList import Control.Monad.Trans.State (runState, modify, gets, put, )--- import Control.Monad (mapM, ) import Data.Tuple.HT (mapSnd, ) --- import qualified Algebra.RealRing as RealRing import qualified Algebra.Additive as Additive import qualified Number.NonNegative as NonNeg import Foreign.Storable (Storable) -import NumericPrelude.Base import NumericPrelude.Numeric
src/Synthesizer/Storable/Filter/NonRecursive.hs view
@@ -30,8 +30,6 @@ import Foreign.Storable (Storable, ) import Foreign.Storable.Tuple () -import Algebra.Module( {- linearComb, -} (*>), )- import Control.Monad (mplus, ) import Data.Maybe.HT (toMaybe, ) import Data.Maybe (fromMaybe, )@@ -43,7 +41,6 @@ import NumericPrelude.Base import NumericPrelude.Numeric as NP-import qualified Prelude as P {- |
src/Synthesizer/Storable/Oscillator.hs view
@@ -28,13 +28,9 @@ import Algebra.Module((*>)) -} import qualified Algebra.Transcendental as Trans--- import qualified Algebra.Field as Field import qualified Algebra.RealRing as RealRing-import qualified Algebra.Additive as Additive import NumericPrelude.Numeric--import qualified Prelude as P import NumericPrelude.Base
src/Test/Main.hs view
@@ -6,9 +6,16 @@ import qualified Test.Sound.Synthesizer.Plain.Interpolation as Interpolation import qualified Test.Sound.Synthesizer.Plain.Oscillator as Oscillator import qualified Test.Sound.Synthesizer.Plain.Wave as Wave+import qualified Test.Sound.Synthesizer.Basic.NumberTheory as NumberTheory import qualified Test.Sound.Synthesizer.Basic.ToneModulation as ToneModulation import qualified Test.Sound.Synthesizer.Plain.ToneModulation as ToneModulationL import qualified Test.Sound.Synthesizer.Generic.ToneModulation as ToneModulationG+import qualified Test.Sound.Synthesizer.Generic.Permutation as Permutation+import qualified Test.Sound.Synthesizer.Generic.Fourier as Fourier+import qualified Test.Sound.Synthesizer.Generic.FourierInteger as FourierInteger+import qualified Test.Sound.Synthesizer.Generic.Filter as FilterG+import qualified Test.Sound.Synthesizer.Generic.Cut as CutG+import qualified Test.Sound.Synthesizer.Causal.Analysis as AnalysisC import qualified Test.Sound.Synthesizer.Storable.Cut as Cut import Data.Tuple.HT (mapFst, )@@ -29,7 +36,14 @@ prefix "Plain.Oscillator" Oscillator.tests : prefix "Plain.Wave" Wave.tests : prefix "Storable.Cut" Cut.tests :+ prefix "Generic.Cut" CutG.tests : prefix "Basic.ToneModulation" ToneModulation.tests : prefix "Plain.ToneModulation" ToneModulationL.tests : prefix "Generic.ToneModulation" ToneModulationG.tests :+ prefix "Generic.Permutation" Permutation.tests :+ prefix "Generic.Fourier" Fourier.tests :+ prefix "Basic.NumberTheory" NumberTheory.tests :+ prefix "Generic.FourierInteger" FourierInteger.tests :+ prefix "Generic.Filter" FilterG.tests :+ prefix "Causal.Analysis" AnalysisC.tests : []
+ src/Test/Sound/Synthesizer/Basic/NumberTheory.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE NoImplicitPrelude #-}+module Test.Sound.Synthesizer.Basic.NumberTheory (tests) where++import Synthesizer.Basic.NumberTheory (Order(Order), )+import qualified Synthesizer.Basic.NumberTheory as NT+import qualified Data.Set as Set++import Test.QuickCheck (Testable, Arbitrary, arbitrary, quickCheck, )++import qualified Algebra.Absolute as Absolute++import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()+++newtype Cardinal a = Cardinal a+ deriving (Show)++instance (Absolute.C a, Arbitrary a) => Arbitrary (Cardinal a) where+ arbitrary = fmap (Cardinal . abs) arbitrary+++newtype Positive a = Positive a+ deriving (Show)++instance (Absolute.C a, Arbitrary a) => Arbitrary (Positive a) where+ arbitrary = fmap (Positive . (1+) . abs) arbitrary+++simple ::+ (Testable t, Arbitrary (wrapper Integer), Show (wrapper Integer)) =>+ (wrapper Integer -> t) -> IO ()+simple = quickCheck++tests :: [(String, IO ())]+tests =+ ("primitiveRootsOfUnity naive vs. power",+ simple $ \(Cardinal m) order ->+ NT.primitiveRootsOfUnityNaive m order+ ==+ NT.primitiveRootsOfUnityPower m order) :+ ("primitiveRootsOfUnity naive vs. fullorbit",+ simple $ \(Cardinal m) order ->+ NT.primitiveRootsOfUnityNaive m order+ ==+ (Set.toAscList $ Set.fromList $+ NT.primitiveRootsOfUnityFullOrbit m order)) :+ ("Carmichael theorem",+ simple $ \(Positive a) (Positive b) ->+ NT.getOrder (NT.maximumOrderOfPrimitiveRootsOfUnity (lcm a b))+ ==+ lcm+ (NT.getOrder (NT.maximumOrderOfPrimitiveRootsOfUnity a))+ (NT.getOrder (NT.maximumOrderOfPrimitiveRootsOfUnity b))) :+ ("maximumOrderOfPrimitiveRootsOfUnity naive vs. integer",+ simple $ \(Positive m) ->+ NT.maximumOrderOfPrimitiveRootsOfUnityNaive m+ ==+ NT.maximumOrderOfPrimitiveRootsOfUnityInteger m) :+ ("number of rootsOfUnityPower, lcm",+ simple $ \(Positive m) ao@(Order a) bo@(Order b) ->+ let g = length . NT.rootsOfUnityPower m+ in g (Order $ lcm a b) == lcm (g ao) (g bo)) :+ ("ringsWithPrimitiveRootsOfUnityAndUnits: minimal modulus",+ quickCheck $ \order@(Order expo) ->+ (head $ NT.ringsWithPrimitiveRootOfUnityAndUnit order)+ ==+ (head $ NT.ringsWithPrimitiveRootsOfUnityAndUnitsNaive+ [order] [expo])) :+ ("combine two rings with primitive roots of certain orders",+ quickCheck $ \m n ->+ let r = lcm+ (head (NT.ringsWithPrimitiveRootOfUnityAndUnit m))+ (head (NT.ringsWithPrimitiveRootOfUnityAndUnit n))+ in NT.hasPrimitiveRootOfUnityInteger r m+ &&+ NT.hasPrimitiveRootOfUnityInteger r n) :+ ("combine many rings with primitive roots of certain orders",+ quickCheck $ \n0 ns0 ->+ let ns = take 3 $ map (\n -> 1 + mod n 10) (n0:ns0)+ order = NT.lcmMulti ns+ in take 3 (NT.ringsWithPrimitiveRootsOfUnityAndUnitsNaive+ (map Order ns) ns)+ ==+ take 3 (NT.ringsWithPrimitiveRootsOfUnityAndUnitsNaive+ [Order order] [order])) :+{-+Unfortunately rings with certain units cannot be combined+while maintaining these elements as units.++Counterexample:+ ringsWithPrimitiveRootOfUnityAndUnit 2 = 3:...+ ringsWithPrimitiveRootOfUnityAndUnit 3 = 7:...+ But in Z_{3·7} the number 3 is no unit.++ ("combine rings with certain units",+ quickCheck $ \(Positive m) (Positive n) ->+ let r = fromIntegral $ lcm+ (head (NT.ringsWithPrimitiveRootOfUnityAndUnit m))+ (head (NT.ringsWithPrimitiveRootOfUnityAndUnit n))+ in PID.coprime r m && PID.coprime r n) :+-}+ ("number of roots of unity lcm",+ quickCheck $ \(Positive n) (Positive k) (Positive l) ->+ let orders = NT.ordersOfRootsOfUnityInteger !! (n-1)+ in lcm (orders!!(k-1)) (orders!!(l-1))+ ==+ orders !! (lcm k l - 1)) :+ ("number of roots of unity vs. primitive roots",+ quickCheck $ \(Positive n) (Positive k) ->+ (sum $ map snd $+ filter (flip divides k . fst) $+ zip+ [1..]+ (NT.ordersOfPrimitiveRootsOfUnityInteger !! (n-1)))+ ==+ NT.ordersOfRootsOfUnityInteger !! (n-1) !! (k-1)) :+ []
src/Test/Sound/Synthesizer/Basic/ToneModulation.hs view
@@ -12,14 +12,9 @@ -- import Test.Utility import qualified Number.NonNegative as NonNeg--- import qualified Number.NonNegativeChunky as Chunky --- import qualified Algebra.RealTranscendental as RealTrans--- import qualified Algebra.Module as Module 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 NumericPrelude.Numeric
+ src/Test/Sound/Synthesizer/Causal/Analysis.hs view
@@ -0,0 +1,32 @@+module Test.Sound.Synthesizer.Causal.Analysis (tests) where++import qualified Synthesizer.Causal.Analysis as AnaC+import qualified Synthesizer.Causal.Process as Causal+import qualified Synthesizer.Plain.Analysis as Ana++import Control.Arrow ((<<<), )++import qualified Data.List.Match as Match++import Test.QuickCheck (quickCheck, )++import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()+++tests :: [(String, IO ())]+tests =+ ("deltaSigmaModulation",+ quickCheck $ \xs ->+ Match.take xs (Ana.deltaSigmaModulation xs)+ ==+ Causal.apply AnaC.deltaSigmaModulation (xs::[Rational])) :+ ("deltaSigmaModulationPositive",+ quickCheck $ \threshold xs ->+ Match.take xs (Ana.deltaSigmaModulationPositive threshold xs)+ ==+ Causal.apply+ (AnaC.deltaSigmaModulationPositive <<<+ Causal.feedConstFst threshold) (xs::[Rational])) :+ []
+ src/Test/Sound/Synthesizer/Generic/Cut.hs view
@@ -0,0 +1,104 @@+module Test.Sound.Synthesizer.Generic.Cut (tests) where++import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.Generic.Signal as SigG++import qualified Synthesizer.Storable.Signal as SigSt++import qualified Synthesizer.ChunkySize.Signal as SigChunky+import qualified Synthesizer.ChunkySize as ChunkySize++import qualified Data.StorableVector as SV+import qualified Data.StorableVector.Lazy.Pattern as SVP++import qualified Synthesizer.State.Signal as SigS++import qualified Data.EventList.Relative.BodyTime as EventList++import qualified Number.NonNegative as NonNeg+import qualified Number.NonNegativeChunky as Chunky++import qualified Numeric.NonNegative.Wrapper as NonNeg98++import Data.Tuple.HT (mapSnd, )++import Test.QuickCheck (quickCheck, )++import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()+++dropMarginRemLength :: NonNeg.Int -> NonNeg.Int -> [Int] -> Bool+dropMarginRemLength nn nm xs =+ let n = NonNeg.toNumber nn+ m = NonNeg.toNumber nm+ (k,ys) = CutG.dropMarginRem n m xs+ in length xs - m == length ys - k++dropMarginRemState :: NonNeg.Int -> NonNeg.Int -> [Int] -> Bool+dropMarginRemState nn nm xs =+ let n = NonNeg.toNumber nn+ m = NonNeg.toNumber nm+ in CutG.dropMarginRem n m (SigS.fromList xs)+ ==+ mapSnd SigS.fromList (CutG.dropMarginRem n m xs)++dropMarginRemSV :: NonNeg.Int -> NonNeg.Int -> [Int] -> Bool+dropMarginRemSV nn nm xs =+ let n = NonNeg.toNumber nn+ m = NonNeg.toNumber nm+ in CutG.dropMarginRem n m (SV.pack xs)+ ==+ mapSnd SV.pack (CutG.dropMarginRem n m xs)++dropMarginRemSVL :: NonNeg.Int -> NonNeg.Int -> ChunkySize.T -> [Int] -> Bool+dropMarginRemSVL nn nm pat xs =+ let n = NonNeg.toNumber nn+ m = NonNeg.toNumber nm+ in CutG.dropMarginRem n m+ (CutG.take (CutG.length pat) xs)+ ==+ mapSnd SigG.toList+ (CutG.dropMarginRem n m+ (SigChunky.fromState pat $+ SigG.toState xs :: SigSt.T Int))++dropMarginRemChunkySize ::+ NonNeg.Int -> NonNeg.Int -> ChunkySize.T -> Int -> Bool+dropMarginRemChunkySize nn nm pat x =+ let n = NonNeg.toNumber nn+ m = NonNeg.toNumber nm+ in CutG.dropMarginRem n m pat+ ==+ mapSnd+ (ChunkySize.fromStorableVectorSize . SVP.length)+ (CutG.dropMarginRem n m+ (SVP.replicate (ChunkySize.toStorableVectorSize pat) x))++dropMarginRemPiecewise ::+ NonNeg.Int -> NonNeg.Int -> ChunkySize.T -> Int -> Bool+dropMarginRemPiecewise nn nm pat x =+ let n = NonNeg.toNumber nn+ m = NonNeg.toNumber nm+ in CutG.dropMarginRem n m pat+ ==+ mapSnd+ (Chunky.fromChunks .+ map (\size -> SigG.LazySize $ NonNeg98.toNumber size) .+ EventList.getTimes)+ (CutG.dropMarginRem n m+ (EventList.fromPairList $ map ((,) x) $+ map (\(SigG.LazySize size) -> NonNeg98.fromNumber size) $+ Chunky.toChunks pat))+++tests :: [(String, IO ())]+tests =+ ("dropMarginRemLength", quickCheck dropMarginRemLength) :+ ("dropMarginRemState", quickCheck dropMarginRemState) :+ ("dropMarginRemSV", quickCheck dropMarginRemSV) :+ ("dropMarginRemSVL", quickCheck dropMarginRemSVL) :+ ("dropMarginRemChunkySize", quickCheck dropMarginRemChunkySize) :+ ("dropMarginRemPiecewise", quickCheck dropMarginRemPiecewise) :+ []
+ src/Test/Sound/Synthesizer/Generic/Filter.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE NoImplicitPrelude #-}+module Test.Sound.Synthesizer.Generic.Filter (tests) where++import qualified Synthesizer.Generic.Filter.NonRecursive as FiltNRG+import qualified Synthesizer.Generic.Cyclic as Cyclic+import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.Plain.Signal as Sig++import qualified Test.Sound.Synthesizer.Plain.NonEmpty as NonEmpty++import Test.QuickCheck (Testable, quickCheck, )++-- import qualified Algebra.Ring as Ring++import qualified Algebra.Laws as Law++import NumericPrelude.Numeric+import NumericPrelude.Base+++simple ::+ (Testable t) =>+ (Sig.T Int -> t) -> IO ()+simple = quickCheck++(=|=) ::+ (Eq sig, CutG.Transform sig) =>+ sig -> sig -> Bool+x =|= y =+ CutG.take 100 x == CutG.take 100 y++tests :: [(String, IO ())]+tests =+ ("identity",+ simple $ Law.identity FiltNRG.generic $ SigG.singleton one) :+ ("commutativity",+ simple $ Law.commutative FiltNRG.generic) :+ ("distributivity",+ simple $ Law.leftDistributive FiltNRG.generic SigG.mix) :+ ("karatsuba finite",+ simple $ \x y -> FiltNRG.generic x y == FiltNRG.karatsubaFinite (*) x y) :+ ("karatsuba finite-infinite",+ simple $ \x y -> FiltNRG.generic x y == FiltNRG.karatsubaFiniteInfinite (*) x y) :+ ("karatsuba infinite",+ simple $ \x y -> FiltNRG.generic x y == FiltNRG.karatsubaInfinite (*) x y) :+ ("karatsuba finite-infinite cycle",+ simple $ \x yn ->+ case NonEmpty.toInfiniteList yn of+ y -> FiltNRG.generic x y =|= FiltNRG.karatsubaFiniteInfinite (*) x y) :+ ("karatsuba infinite cycle",+ simple $ \x yn ->+ case NonEmpty.toInfiniteList yn of+ y -> FiltNRG.generic x y =|= FiltNRG.karatsubaInfinite (*) x y) :+ ("convolve triple",+ quickCheck $ \x y ->+ Cyclic.sumAndConvolveTriple x y ==+ Cyclic.sumAndConvolveTripleAlt x (y :: Cyclic.Triple Integer)) :+ ("periodic summation",+ simple $ \x y n ->+ let periodic = Cyclic.fromSignal SigG.defaultLazySize (1 + abs n)+ in Cyclic.convolve (periodic x) (periodic y) ==+ periodic (FiltNRG.generic x y)) :+ []
+ src/Test/Sound/Synthesizer/Generic/Fourier.hs view
@@ -0,0 +1,152 @@+{-# LANGUAGE NoImplicitPrelude #-}+module Test.Sound.Synthesizer.Generic.Fourier (tests) where++import qualified Synthesizer.Generic.Fourier as Fourier+import qualified Synthesizer.Generic.Cyclic as Cyclic+import qualified Synthesizer.Generic.Filter.NonRecursive as FiltNRG+import qualified Synthesizer.Generic.Analysis as AnaG+import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Generic.Signal2 as SigG2+import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.Storable.Signal as SigSt+import qualified Synthesizer.State.Signal as SigS++import Test.QuickCheck (Testable, Arbitrary, arbitrary, quickCheck, )+import Test.Utility (approxEqualAbs, approxEqualComplexAbs, )++import qualified Number.Complex as Complex++import qualified Algebra.Ring as Ring+import qualified Algebra.Additive as Additive++import Control.Monad (liftM2, )++import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()+++tolerance :: Double+tolerance = 1e-10++normalize ::+ SigSt.T (Complex.T Double) -> SigSt.T (Complex.T Double)+normalize xs =+ FiltNRG.amplifyVector+ (recip $ max (0.1::Double) $ AnaG.volumeVectorMaximum xs) xs++newtype Normed = Normed (SigSt.T (Complex.T Double))+ deriving (Show)++instance Arbitrary Normed where+ arbitrary = fmap (Normed . normalize) arbitrary+++data Normed2 =+ Normed2+ (SigSt.T (Complex.T Double))+ (SigSt.T (Complex.T Double))+ deriving (Show)++instance Arbitrary Normed2 where+ arbitrary =+ liftM2+ (\x y ->+ let len = min (CutG.length x) (CutG.length y)+ in Normed2+ (normalize $ CutG.take len x)+ (normalize $ CutG.take len y))+ arbitrary+ arbitrary+++-- could be moved to NumericPrelude+class Complex a where+ conjugate :: a -> a++instance (Additive.C a) => Complex (Complex.T a) where+ conjugate = Complex.conjugate++scalarProduct ::+ (SigG.Read sig y, Ring.C y, Complex y) =>+ sig y -> sig y -> y+scalarProduct xs ys =+ SigS.sum $+ SigS.zipWith (*)+ (SigG.toState xs)+ (SigS.map conjugate $ SigG.toState ys)++(=~=) ::+ SigSt.T (Complex.T Double) ->+ SigSt.T (Complex.T Double) ->+ Bool+(=~=) xs ys =+ SigG.length xs == SigG.length ys &&+ (SigG.foldR (&&) True $+ SigG2.zipWith (approxEqualComplexAbs tolerance) xs ys)++simple ::+ (Testable t) =>+ (SigSt.T (Complex.T Double) -> t) -> IO ()+simple = quickCheck++tests :: [(String, IO ())]+tests =+ ("fourier inverse",+ quickCheck $ \(Normed x) ->+ x =~=+ (FiltNRG.amplify (recip $ fromIntegral $ SigG.length x) $+ Fourier.transformBackward $ Fourier.transformForward x)) :+ ("double fourier = reverse",+ quickCheck $ \(Normed x) ->+ x =~=+ (Cyclic.reverse $+ FiltNRG.amplify (recip $ fromIntegral $ SigG.length x) $+ Fourier.transformForward $+ Fourier.transformForward x)) :+ ("fourier of reverse",+ quickCheck $ \(Normed x) ->+ Cyclic.reverse (Fourier.transformForward x) =~=+ Fourier.transformForward (Cyclic.reverse x)) :+ ("fourier of conjugate",+ quickCheck $ \(Normed x) ->+ (SigG.map Complex.conjugate $ Fourier.transformForward x)+ =~=+ (Fourier.transformForward $+ SigG.map Complex.conjugate $ Cyclic.reverse x)) :+ ("additivity",+ quickCheck $ \(Normed2 x y) ->+ SigG.mix (Fourier.transformForward x) (Fourier.transformForward y)+ =~=+ Fourier.transformForward (SigG.mix x y)) :+ ("isometry",+ simple $ \xs x0 ->+ let x = normalize (SigG.cons x0 xs)+ in approxEqualAbs tolerance+ (AnaG.volumeVectorEuclideanSqr $ Fourier.transformForward x)+ (fromIntegral (SigG.length x) *+ AnaG.volumeVectorEuclideanSqr x)) :+ ("unitarity",+ quickCheck $ \(Normed2 x y) ->+ approxEqualComplexAbs tolerance+ (scalarProduct+ (Fourier.transformForward x) (Fourier.transformForward y))+ (fromIntegral (SigG.length x) * scalarProduct x y)) :+ ("convolution",+ quickCheck $ \(Normed2 x y) ->+ SigG.zipWith (*)+ (Fourier.transformForward x)+ (Fourier.transformForward y)+ =~=+ Fourier.transformForward (Cyclic.convolve x y)) :+ ("convolution cyclic",+ quickCheck $ \(Normed2 x y) ->+ Fourier.convolveCyclic x y+ =~=+ Cyclic.convolve x y) :+ ("convolution long",+ quickCheck $ \(Normed x) (Normed y) ->+ FiltNRG.karatsubaFinite (*) x y+ =~=+ Fourier.convolveWithWindow (Fourier.window x) y) :+ []
+ src/Test/Sound/Synthesizer/Generic/FourierInteger.hs view
@@ -0,0 +1,178 @@+{-# LANGUAGE NoImplicitPrelude #-}+module Test.Sound.Synthesizer.Generic.FourierInteger (tests) where++import qualified Synthesizer.Generic.Fourier as Fourier+import qualified Synthesizer.Generic.Cyclic as Cyclic+import qualified Synthesizer.Generic.Filter.NonRecursive as FiltNRG+import qualified Synthesizer.Generic.Signal as SigG+import qualified Synthesizer.Generic.Cut as CutG+import qualified Synthesizer.State.Signal as SigS+import qualified Synthesizer.Plain.Signal as Sig++import Test.QuickCheck (Testable, Arbitrary, arbitrary, quickCheck, )++import qualified Synthesizer.Basic.NumberTheory as NT++import qualified Number.ResidueClass.Check as RC+import Number.ResidueClass.Check ((/:), )++import qualified Algebra.ToInteger as ToInteger+import qualified Algebra.IntegralDomain as Integral+import qualified Algebra.Ring as Ring++import Control.Monad (liftM2, )++import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()+++newtype Modulus a = Modulus a+ deriving (Show)++instance Ring.C a => Arbitrary (Modulus a) where+ arbitrary = fmap (Modulus . (2+) . fromInteger) arbitrary+++data ModularSignal =+ ModularSignal (Modulus Integer) (Sig.T (RC.T Integer))+ deriving (Show)++instance Arbitrary ModularSignal where+ arbitrary =+ fmap (uncurry ModularSignal . signal) arbitrary+++data ModularSignal2 =+ ModularSignal2+ (Modulus Integer) (Sig.T (RC.T Integer)) (Sig.T (RC.T Integer))+ deriving (Show)++instance Arbitrary ModularSignal2 where+ arbitrary =+ liftM2+ (\x y ->+ let len = min (CutG.length x) (CutG.length y)+ m = NT.fastFourierRing len+ in ModularSignal2+ (Modulus m)+ (fmap (/: m) $ CutG.take len x)+ (fmap (/: m) $ CutG.take len y))+ arbitrary+ arbitrary++scalarProduct ::+ Modulus Integer ->+ Sig.T (RC.T Integer) -> Sig.T (RC.T Integer) ->+ RC.T Integer+scalarProduct (Modulus m) xs ys =+ SigS.foldL (+) (RC.zero m) $+ SigS.zipWith (*)+ (SigG.toState xs)+ (SigG.toState ys)++{-+signal ::+ Integral.C a =>+ Modulus a -> Sig.T a -> Sig.T (RC.T a)+signal (Modulus a) = fmap (/: a)+-}++signal ::+ Sig.T Integer -> (Modulus Integer, Sig.T (RC.T Integer))+signal xs =+ let m = NT.fastFourierRing $ length xs+ in (Modulus m, fmap (/: m) xs)++modular ::+ (Integral.C a, ToInteger.C b) =>+ Modulus a -> b -> RC.T a+modular (Modulus m) =+ RC.fromRepresentative m . fromIntegral+++simple ::+ (Testable t) =>+ (Sig.T Integer -> t) -> IO ()+simple = quickCheck++tests :: [(String, IO ())]+tests =+ ("fourier inverse",+ quickCheck $ \(ModularSignal m x) ->+ (Fourier.transformBackward $ Fourier.transformForward x)+ ==+ FiltNRG.amplify (modular m $ length x) x) :+ ("double fourier = reverse",+ quickCheck $ \(ModularSignal m x) ->+ (Cyclic.reverse $+ Fourier.transformForward $+ Fourier.transformForward x)+ ==+ FiltNRG.amplify (modular m $ length x) x) :+ ("fourier of reverse",+ quickCheck $ \(ModularSignal _m x) ->+ Cyclic.reverse (Fourier.transformForward x) ==+ Fourier.transformForward (Cyclic.reverse x)) :+ ("homogenity",+ quickCheck $ \(ModularSignal m x) y ->+ (FiltNRG.amplify (modular m (y::Integer)) $+ Fourier.transformForward x)+ ==+ (Fourier.transformForward $+ FiltNRG.amplify (modular m y) x)) :+ ("additivity",+ quickCheck $ \(ModularSignal2 _m x y) ->+ SigG.mix (Fourier.transformForward x) (Fourier.transformForward y)+ ==+ Fourier.transformForward (SigG.mix x y)) :+{-+ ("isometry",+ simple $ \xs x0 ->+ let (m,x) = signal (SigG.cons x0 xs)+ in (AnaG.volumeVectorEuclideanSqr $ Fourier.transformForward x)+ ==+ (modular m (SigG.length x) *+ AnaG.volumeVectorEuclideanSqr x)) :+-}+ ("unitarity",+ quickCheck $ \(ModularSignal2 m x y) ->+ {-+ since there is no equivalent of a complex conjugate+ we have to take the scalar product with the backwards transform.+ -}+ scalarProduct m+ (Fourier.transformForward x) (Fourier.transformBackward y)+ ==+ modular m (length x) * scalarProduct m x y) :+ ("convolution",+ quickCheck $ \(ModularSignal2 _m x y) ->+ SigG.zipWith (*)+ (Fourier.transformForward x)+ (Fourier.transformForward y)+ ==+ Fourier.transformForward (Cyclic.convolve x y)) :+ ("convolution cyclic",+ quickCheck $ \(ModularSignal2 _m x y) ->+ Fourier.convolveCyclic x y+ ==+ Cyclic.convolve x y) :+ ("convolution long",+ simple $ \x0 y0 ->+ let m = Modulus $ NT.fastFourierRing $+ 2 * (NT.ceilingPowerOfTwo $ length x0)+ x = fmap (modular m) x0+ y = fmap (modular m) y0+ in fmap (modular m) (FiltNRG.karatsubaFinite (*) x0 y0)+ ==+ Fourier.convolveWithWindow (Fourier.window x) y) :+ ("convolution long modular",+ simple $ \x0 y0 ->+ let m = Modulus $ NT.fastFourierRing $+ 2 * (NT.ceilingPowerOfTwo $ length x0)+ x = fmap (modular m) x0+ y = fmap (modular m) (y0 :: Sig.T Integer)+ in FiltNRG.karatsubaFinite (*) x y+ ==+ Fourier.convolveWithWindow (Fourier.window x) y) :+ []
+ src/Test/Sound/Synthesizer/Generic/Permutation.hs view
@@ -0,0 +1,45 @@+{-+wish list:+ - custom Permutation type with Arbitrary instance+-}+{-# LANGUAGE NoImplicitPrelude #-}+module Test.Sound.Synthesizer.Generic.Permutation (tests) where++import qualified Synthesizer.Generic.Permutation as Permutation++import Test.QuickCheck (quickCheck, )++import NumericPrelude.Numeric+import NumericPrelude.Base+import Prelude ()+++tests :: [(String, IO ())]+tests =+ ("inverse transposition",+ quickCheck $ \n0 m0 ->+ let n = mod n0 100+ m = mod m0 100+ in Permutation.inverse (Permutation.transposition n m)+ ==+ Permutation.transposition m n) :+ ("inverse skewGrid",+ quickCheck $ \n0 m0 ->+ let g = gcd n0 m0+ (n,m) = if g==0 then (0,0) else (abs (div n0 g), abs (div m0 g))+ in Permutation.inverse (Permutation.skewGrid n m)+ ==+ Permutation.skewGridInv n m) :+ ("inverse skewGridCRT",+ quickCheck $ \n0 m0 ->+ let g = gcd n0 m0+ (n,m) = if g==0 then (0,0) else (abs (div n0 g), abs (div m0 g))+ in Permutation.inverse (Permutation.skewGridCRT n m)+ ==+ Permutation.skewGridCRTInv n m) :+ {-+ reverse (multiplicative (generator n) n)+ ==+ multiplicative (recip $ generator n) n+ -}+ []
src/Test/Sound/Synthesizer/Generic/ToneModulation.hs view
@@ -35,12 +35,7 @@ import qualified Number.NonNegative as NonNeg --- import qualified Algebra.RealTranscendental as RealTrans--- import qualified Algebra.Module as Module 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 Data.List.HT (viewL, takeWhileJust, )
src/Test/Sound/Synthesizer/Plain/Analysis.hs view
@@ -6,8 +6,6 @@ import qualified Algebra.RealField as RealField import qualified Algebra.Field as Field import qualified Algebra.RealRing as RealRing-import qualified Algebra.Ring as Ring-import qualified Algebra.Additive as Additive import qualified Algebra.NormedSpace.Maximum as NormedMax import qualified Algebra.NormedSpace.Euclidean as NormedEuc
src/Test/Sound/Synthesizer/Plain/Oscillator.hs view
@@ -8,16 +8,8 @@ -- import qualified Test.Sound.Synthesizer.Plain.Interpolation as InterpolationTest import Test.QuickCheck (test, {- Property, (==>), -} )--- import Test.Utility --- import qualified Number.NonNegative as NonNeg---- import qualified Algebra.RealTranscendental as RealTrans--- import qualified Algebra.Module as Module 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 NumericPrelude.Numeric
src/Test/Sound/Synthesizer/Plain/ToneModulation.hs view
@@ -20,7 +20,7 @@ import qualified Test.Sound.Synthesizer.Plain.NonEmpty as NonEmpty import qualified Test.Sound.Synthesizer.Plain.Interpolation as InterpolationTest -import Test.QuickCheck (quickCheck, Property, (==>), Arbitrary, arbitrary, )+import Test.QuickCheck (quickCheck, Property, (==>), ) import Test.Utility (ArbChar, ) import qualified Number.NonNegative as NonNeg@@ -29,11 +29,8 @@ import qualified Algebra.RealTranscendental as RealTrans import qualified Algebra.Module as Module 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 Control.Monad (liftM2, ) import Data.List.HT (isAscending, ) import Data.Ord.HT (limit, ) import Data.Tuple.HT (mapPair, mapSnd, )
src/Test/Sound/Synthesizer/Plain/Wave.hs view
@@ -9,11 +9,7 @@ import qualified Number.NonNegative as NonNeg import qualified Algebra.RealTranscendental as RealTrans--- import qualified Algebra.Module as Module--- 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 Control.Monad (liftM, liftM2, ) import System.Random (Random)
src/Test/Sound/Synthesizer/Storable/Cut.hs view
@@ -17,9 +17,6 @@ import Test.QuickCheck (quickCheck, ) import Test.Utility (equalList, ) --- import qualified Algebra.Ring as Ring--- import qualified Algebra.Additive as Additive- import NumericPrelude.Numeric import NumericPrelude.Base import Prelude ()
src/Test/Utility.hs view
@@ -3,9 +3,11 @@ import Test.QuickCheck (Arbitrary(arbitrary)) -import qualified Algebra.RealRing as RealRing-import qualified Algebra.Ring as Ring+import qualified Number.Complex as Complex +import qualified Algebra.RealRing as RealRing++import qualified Data.List.HT as ListHT import qualified Data.Char as Char import NumericPrelude.Base@@ -14,14 +16,17 @@ equalList :: Eq a => [a] -> Bool equalList xs =- -- 'drop 1' instead of 'take' for suppression of error- and (zipWith (==) xs (drop 1 xs))+ and (ListHT.mapAdjacent (==) xs) approxEqual :: (RealRing.C a) => a -> a -> a -> Bool approxEqual eps x y = 2 * abs (x-y) <= eps * (abs x + abs y) +approxEqualAbs :: (RealRing.C a) => a -> a -> a -> Bool+approxEqualAbs eps x y =+ abs (x-y) <= eps+ approxEqualListRel :: (RealRing.C a) => a -> [a] -> Bool approxEqualListRel eps xs = let n = fromIntegral $ length xs@@ -32,6 +37,20 @@ let n = fromIntegral $ length xs s = sum xs in sum (map (\x -> abs (n*x-s)) xs) <= eps+++approxEqualComplex ::+ (RealRing.C a) =>+ a -> Complex.T a -> Complex.T a -> Bool+approxEqualComplex eps x y =+ 2 * Complex.magnitudeSqr (x-y)+ <= eps^2 * (Complex.magnitudeSqr x + Complex.magnitudeSqr y)++approxEqualComplexAbs ::+ (RealRing.C a) =>+ a -> Complex.T a -> Complex.T a -> Bool+approxEqualComplexAbs eps x y =+ Complex.magnitudeSqr (x-y) <= eps^2 -- see event-list
synthesizer-core.cabal view
@@ -1,5 +1,5 @@ Name: synthesizer-core-Version: 0.4.0.4+Version: 0.4.1 License: GPL License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>@@ -18,6 +18,10 @@ -- the Overview module does not really fit into one of the part packages -- For an overview of the organization of the package -- and the discussion of various design issues see "Synthesizer.Overview".+ .+ Functions:+ Oscillators, Noise generators, Frequency filters,+ Fast Fourier transform for computation of frequency spectrum Stability: Experimental Tested-With: GHC==6.4.1, GHC==6.8.2, GHC==6.10.4 Cabal-Version: >=1.6@@ -48,7 +52,7 @@ Source-Repository this- Tag: 0.4.0.4+ Tag: 0.4.1 Type: darcs Location: http://code.haskell.org/synthesizer/core/ @@ -63,7 +67,8 @@ transformers >=0.2 && <0.3, event-list >=0.1 && <0.2, non-negative >=0.1 && <0.2,- numeric-prelude >=0.2 && <0.3,+ explicit-exception >=0.1.6 && <0.2,+ numeric-prelude >=0.2.1 && <0.3, numeric-quest >=0.1 && <0.2, utility-ht >=0.0.5 && <0.1, filepath >=1.1 && <1.2,@@ -85,7 +90,7 @@ Build-Depends: base >= 3 && <4 Build-Depends: array >=0.1 && <0.4,- containers >=0.1 && <0.4,+ containers >=0.1 && <0.5, random >=1.0 && <2.0, process >=1.0 && <1.1 Else@@ -184,23 +189,27 @@ Synthesizer.State.ToneModulation Synthesizer.Causal.Process Synthesizer.Causal.Arrow+ Synthesizer.Causal.Analysis Synthesizer.Causal.Cut Synthesizer.Causal.Displacement Synthesizer.Causal.Interpolation Synthesizer.Causal.Oscillator Synthesizer.Causal.Oscillator.Core Synthesizer.Causal.ToneModulation+ Synthesizer.Causal.Spatial Synthesizer.Causal.Filter.NonRecursive Synthesizer.Causal.Filter.Recursive.Integration Synthesizer.Generic.Analysis Synthesizer.Generic.Cut Synthesizer.Generic.Control+ Synthesizer.Generic.Cyclic Synthesizer.Generic.Displacement Synthesizer.Generic.Filter.NonRecursive Synthesizer.Generic.Filter.Delay Synthesizer.Generic.Filter.Recursive.Integration Synthesizer.Generic.Filter.Recursive.MovingAverage Synthesizer.Generic.Filter.Recursive.Comb+ Synthesizer.Generic.Fourier Synthesizer.Generic.Interpolation Synthesizer.Generic.Loop Synthesizer.Generic.Noise@@ -219,6 +228,9 @@ Other-Modules: Synthesizer.Basic.ComplexModule+ Synthesizer.Basic.NumberTheory+ Synthesizer.Generic.Permutation+ Synthesizer.Generic.LengthSignal Executable test@@ -243,9 +255,37 @@ Test.Sound.Synthesizer.Plain.ToneModulation Test.Sound.Synthesizer.Plain.Wave Test.Sound.Synthesizer.Basic.ToneModulation+ Test.Sound.Synthesizer.Basic.NumberTheory+ Test.Sound.Synthesizer.Generic.Cut Test.Sound.Synthesizer.Generic.ToneModulation+ Test.Sound.Synthesizer.Generic.Permutation+ Test.Sound.Synthesizer.Generic.Fourier+ Test.Sound.Synthesizer.Generic.FourierInteger+ Test.Sound.Synthesizer.Generic.Filter Test.Sound.Synthesizer.Storable.Cut+ Test.Sound.Synthesizer.Causal.Analysis Main-Is: Test/Main.hs+++Executable fouriertest+ If flag(buildProfilers)+ Build-Depends:+ storablevector >=0.2.7 && <0.3,+ utility-ht >=0.0.5 && <0.1,+ storable-tuple >=0.0.1 && <0.1,+ numeric-prelude >=0.2 && <0.3,+ timeit >=1.0 && <1.1,+ base >=4 && <5+ Else+ Buildable: False++ GHC-Options: -Wall -auto-all+ Hs-Source-Dirs: speedtest, src+ If flag(category)+ Hs-Source-Dirs: src-4+ Else+ Hs-Source-Dirs: src-3+ Main-Is: Fourier.hs Executable speedtest If !flag(buildProfilers)