synthesizer-0.0.3: src/Synthesizer/Generic/Signal.hs
{- 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)
-}