{- OPTIONS_GHC -fglasgow-exts -} {- Unfortunately we have to use the SampledValue constraint also for lists, which means that we can only use Storable values for signals. Maybe we can improve this situation using associated types. -} module Synthesizer.Generic.Signal where import qualified Algebra.Module as Module import qualified Algebra.Additive as Additive import qualified Synthesizer.Generic.SampledValue as Sample import qualified Synthesizer.Plain.Modifier as Modifier import Control.Monad.State (State, runState, ) import qualified Data.List as List import Synthesizer.Utility (fst3, snd3, thd3) import Prelude (Bool, Int, Maybe(Just), maybe, fst, snd, flip, uncurry, (.), not, ) class C sig where empty :: (Sample.C y) => sig y null :: (Sample.C y) => sig y -> Bool cons :: (Sample.C y) => y -> sig y -> sig y fromList :: (Sample.C y) => [y] -> sig y toList :: (Sample.C y) => sig y -> [y] repeat :: (Sample.C y) => y -> sig y cycle :: (Sample.C y) => sig y -> sig y replicate :: (Sample.C y) => Int -> y -> sig y iterate :: (Sample.C y) => (y -> y) -> y -> sig y iterateAssoc :: (Sample.C y) => (y -> y -> y) -> y -> sig y unfoldR :: (Sample.C b) => (a -> Maybe (b,a)) -> a -> sig b map :: (Sample.C a, Sample.C b) => (a -> b) -> (sig a -> sig b) mix :: (Sample.C y, Additive.C y) => sig y -> sig y -> sig y zipWith :: (Sample.C a, Sample.C b, Sample.C c) => (a -> b -> c) -> (sig a -> sig b -> sig c) {- zipWithTails :: (Sample.C a, Sample.C b, Sample.C c) => (a -> T b -> c) -> T a -> T b -> T c -} scanL :: (Sample.C a, Sample.C b) => (a -> b -> a) -> a -> sig b -> sig a foldL :: (Sample.C b) => (a -> b -> a) -> a -> sig b -> a viewL :: (Sample.C a) => sig a -> Maybe (a, sig a) viewR :: (Sample.C a) => sig a -> Maybe (sig a, a) length :: (Sample.C y) => sig y -> Int take :: (Sample.C y) => Int -> sig y -> sig y drop :: (Sample.C y) => Int -> sig y -> sig y dropMarginRem :: (Sample.C y) => Int -> Int -> sig y -> (Int, sig y) splitAt :: (Sample.C y) => Int -> sig y -> (sig y, sig y) takeWhile :: (Sample.C y) => (y -> Bool) -> sig y -> sig y dropWhile :: (Sample.C y) => (y -> Bool) -> sig y -> sig y span :: (Sample.C y) => (y -> Bool) -> sig y -> (sig y, sig y) append :: (Sample.C y) => sig y -> sig y -> sig y concat :: (Sample.C y) => [sig y] -> sig y reverse :: (Sample.C y) => sig y -> sig y {- mapAccumL :: (Sample.C x, Sample.C y) => (acc -> x -> (acc, y)) -> acc -> sig x -> (acc, sig y) mapAccumR :: (Sample.C x, Sample.C y) => (acc -> x -> (acc, y)) -> acc -> sig x -> (acc, sig y) -} crochetL :: (Sample.C x, Sample.C y) => (x -> acc -> Maybe (y, acc)) -> acc -> sig x -> sig y {-# INLINE sum #-} sum :: (Additive.C a, Sample.C a, C sig) => sig a -> a sum = foldL (Additive.+) Additive.zero {- {-# INLINE tails #-} tails :: (Sample.C y, C sig) => sig y -> [sig y] tails = List.unfoldr (fmap (\x -> (x, fmap snd (viewL x)))) . Just -} {-# INLINE zapWith #-} zapWith :: (Sample.C a, Sample.C b, C sig) => (a -> a -> b) -> sig a -> sig b zapWith f xs0 = let xs1 = maybe empty snd (viewL xs0) in zipWith f xs0 xs1 {-# INLINE zip #-} zip :: (Sample.C a, Sample.C b, C sig) => sig a -> sig b -> sig (a,b) zip = zipWith (,) {-# INLINE unzip #-} unzip :: (Sample.C a, Sample.C b, C sig) => sig (a,b) -> (sig a, sig b) unzip xs = (map fst xs, map snd xs) {-# INLINE unzip3 #-} unzip3 :: (Sample.C a, Sample.C b, Sample.C c, C sig) => sig (a,b,c) -> (sig a, sig b, sig c) unzip3 xs = (map fst3 xs, map snd3 xs, map thd3 xs) {-# INLINE modifyStatic #-} modifyStatic :: (Sample.C a, Sample.C b, C sig) => Modifier.Simple s ctrl a b -> ctrl -> sig a -> sig b modifyStatic (Modifier.Simple state proc) control x = crochetL (\a acc -> Just (runState (proc control a) acc)) state x {-| Here the control may vary over the time. -} {-# INLINE modifyModulated #-} modifyModulated :: (Sample.C a, Sample.C b, Sample.C ctrl, C sig) => Modifier.Simple s ctrl a b -> sig ctrl -> sig a -> sig b modifyModulated (Modifier.Simple state proc) control x = crochetL (\ca acc -> Just (runState (uncurry proc ca) acc)) state (zip control x) -- cf. Module.linearComb {-# INLINE linearComb #-} linearComb :: (Module.C t y, Sample.C t, Sample.C y, C sig) => sig t -> sig y -> y linearComb ts ys = sum (zipWith (Module.*>) ts ys) {-# INLINE sliceVert #-} sliceVert :: (Sample.C y, C sig) => Int -> sig y -> [sig y] sliceVert n = List.map (take n) . List.takeWhile (not . null) . List.iterate (drop n) {-# INLINE extendConstant #-} extendConstant :: (Sample.C y, C sig) => sig y -> sig y extendConstant xt = maybe empty (append xt . repeat . snd) (viewR xt) -- comonadic 'bind' -- only non-empty suffixes are processed {-# INLINE mapTails #-} mapTails :: (Sample.C a, Sample.C b, C sig) => (sig a -> b) -> sig a -> sig b mapTails f = unfoldR (\xs -> do (_,ys) <- viewL xs Just (f xs, ys)) -- only non-empty suffixes are processed {-# INLINE zipWithTails #-} zipWithTails :: (Sample.C a, Sample.C b, Sample.C c, C sig) => (a -> sig b -> c) -> sig a -> sig b -> sig c zipWithTails f = flip (crochetL (\x ys0 -> do (_,ys) <- viewL ys0 Just (f x ys0, ys))) {- instance (Additive.C y, Sample.C y, C sig) => Additive.C (sig y) where (+) = mix negate = map Additive.negate -} {- This does not work, because we can constrain only the instances of Data but this is not checked when implementing methods of C. class Data sig y where class C sig where add :: (Data sig y, Additive.C y) => sig y -> sig y -> sig y map :: (Data sig a, Data sig b) => (a -> b) -> (sig a -> sig b) zipWith :: (Data sig a, Data sig b, Data sig c) => (a -> b -> c) -> (sig a -> sig b -> sig c) -} {- This does not work, because we would need type parameters for all occuring element types. class C sig y where add :: (Additive.C y) => sig y -> sig y -> sig y map :: C sig a => (a -> y) -> (sig a -> sig y) zipWith :: (a -> b -> y) -> (sig a -> sig b -> sig y) -}