{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, OverloadedStrings #-}
module Sound.Tidal.Core where
import Prelude hiding ((<*), (*>))
import Sound.Tidal.Pattern
import Sound.Tidal.Utils
import qualified Data.Map.Strict as Map
import Data.Fixed (mod')
silence :: Pattern a
silence = empty
sig :: (Time -> a) -> Pattern a
sig f = Pattern Analog q
where q (State (s,e) _) | s > e = []
| otherwise = [(((s,e), (s,e)), f (s+((e-s)/2)))]
sine :: Fractional a => Pattern a
sine = sig $ \t -> ((sin_rat $ (pi :: Double) * 2 * (fromRational t)) + 1) / 2
where sin_rat = fromRational . toRational . sin
cosine :: Fractional a => Pattern a
cosine = 0.25 `rotR` sine
saw :: (Fractional a, Real a) => Pattern a
saw = sig $ \t -> mod' (fromRational t) 1
isaw :: (Fractional a, Real a) => Pattern a
isaw = (1-) <$> saw
tri :: (Fractional a, Real a) => Pattern a
tri = append saw (rev saw)
square :: (Fractional a, Real a) => Pattern a
square = sig $
\t -> fromIntegral $ ((floor $ (mod' (fromRational t :: Double) 1) * 2) :: Integer)
envL :: Pattern Double
envL = sig $ \t -> max 0 $ min (fromRational t) 1
envLR :: Pattern Double
envLR = (1-) <$> envL
envEq :: Pattern Double
envEq = sig $ \t -> sqrt (sin (pi/2 * (max 0 $ min (fromRational (1-t)) 1)))
envEqR :: Pattern Double
envEqR = sig $ \t -> sqrt (cos (pi/2 * (max 0 $ min (fromRational (1-t)) 1)))
class Unionable a where
union :: a -> a -> a
instance Unionable a where
union = const
instance {-# OVERLAPPING #-} Unionable ControlMap where
union = Map.union
(|+|) :: (Applicative a, Num b) => a b -> a b -> a b
a |+| b = (+) <$> a <*> b
(|+ ) :: Num a => Pattern a -> Pattern a -> Pattern a
a |+ b = (+) <$> a <* b
( +|) :: Num a => Pattern a -> Pattern a -> Pattern a
a +| b = (+) <$> a *> b
(|/|) :: (Applicative a, Fractional b) => a b -> a b -> a b
a |/| b = (/) <$> a <*> b
(|/ ) :: Fractional a => Pattern a -> Pattern a -> Pattern a
a |/ b = (/) <$> a <* b
( /|) :: Fractional a => Pattern a -> Pattern a -> Pattern a
a /| b = (/) <$> a *> b
(|*|) :: (Applicative a, Num b) => a b -> a b -> a b
a |*| b = (*) <$> a <*> b
(|* ) :: Num a => Pattern a -> Pattern a -> Pattern a
a |* b = (*) <$> a <* b
( *|) :: Num a => Pattern a -> Pattern a -> Pattern a
a *| b = (*) <$> a *> b
(|-|) :: (Applicative a, Num b) => a b -> a b -> a b
a |-| b = (-) <$> a <*> b
(|- ) :: Num a => Pattern a -> Pattern a -> Pattern a
a |- b = (-) <$> a <* b
( -|) :: Num a => Pattern a -> Pattern a -> Pattern a
a -| b = (-) <$> a *> b
(|%|) :: (Applicative a, Real b) => a b -> a b -> a b
a |%| b = mod' <$> a <*> b
(|% ) :: Real a => Pattern a -> Pattern a -> Pattern a
a |% b = mod' <$> a <* b
( %|) :: Real a => Pattern a -> Pattern a -> Pattern a
a %| b = mod' <$> a *> b
(|>|) :: (Applicative a, Unionable b) => a b -> a b -> a b
a |>| b = (flip union) <$> a <*> b
(|> ) :: Unionable a => Pattern a -> Pattern a -> Pattern a
a |> b = (flip union) <$> a <* b
( >|) :: Unionable a => Pattern a -> Pattern a -> Pattern a
a >| b = (flip union) <$> a *> b
(|<|) :: (Applicative a, Unionable b) => a b -> a b -> a b
a |<| b = union <$> a <*> b
(|< ) :: Unionable a => Pattern a -> Pattern a -> Pattern a
a |< b = union <$> a <* b
( <|) :: Unionable a => Pattern a -> Pattern a -> Pattern a
a <| b = union <$> a *> b
(#) :: Unionable b => Pattern b -> Pattern b -> Pattern b
(#) = (|>)
fromList :: [a] -> Pattern a
fromList = fastCat . map pure
listToPat :: [a] -> Pattern a
listToPat = fromList
fromMaybes :: [Maybe a] -> Pattern a
fromMaybes = fastcat . map f
where f Nothing = silence
f (Just x) = pure x
run :: (Enum a, Num a) => Pattern a -> Pattern a
run = (>>= _run)
_run :: (Enum a, Num a) => a -> Pattern a
_run n = fromList [0 .. n-1]
scan :: (Enum a, Num a) => Pattern a -> Pattern a
scan = (>>= _scan)
_scan :: (Enum a, Num a) => a -> Pattern a
_scan n = slowcat $ map _run [1 .. n]
append :: Pattern a -> Pattern a -> Pattern a
append a b = cat [a,b]
cat :: [Pattern a] -> Pattern a
cat [] = silence
cat ps = Pattern Digital q
where n = length ps
q st = concatMap (f st) $ arcCyclesZW (arc st)
f st a = query (withResultTime (+offset) p) $ st {arc = mapBoth (subtract offset) a}
where p = ps !! i
cyc = (floor $ fst a) :: Int
i = cyc `mod` n
offset = (fromIntegral $ cyc - ((cyc - i) `div` n)) :: Time
slowCat :: [Pattern a] -> Pattern a
slowCat = cat
slowcat :: [Pattern a] -> Pattern a
slowcat = slowCat
slowAppend :: Pattern a -> Pattern a -> Pattern a
slowAppend = append
fastAppend :: Pattern a -> Pattern a -> Pattern a
fastAppend a b = _fast 2 $ append a b
fastCat :: [Pattern a] -> Pattern a
fastCat ps = _fast (toTime $ length ps) $ cat ps
fastcat :: [Pattern a] -> Pattern a
fastcat = fastCat
timeCat :: [(Time, Pattern a)] -> Pattern a
timeCat tps = stack $ map (\(s,e,p) -> compress (s/total, e/total) p) $ arrange 0 tps
where total = sum $ map fst tps
arrange :: Time -> [(Time, Pattern a)] -> [(Time, Time, Pattern a)]
arrange _ [] = []
arrange t ((t',p):tps) = (t,t+t',p):(arrange (t+t') tps)
overlay :: Pattern a -> Pattern a -> Pattern a
overlay p@(Pattern Analog _) p'@(Pattern Analog _) = Pattern Analog $ \st -> (query p st) ++ (query p' st)
overlay p p' = Pattern Digital $ \st -> (query p st) ++ (query p' st)
(<>) :: Pattern a -> Pattern a -> Pattern a
(<>) = overlay
stack :: [Pattern a] -> Pattern a
stack = foldr overlay silence
(<~) :: Pattern Time -> Pattern a -> Pattern a
(<~) = tParam rotL
(~>) :: Pattern Time -> Pattern a -> Pattern a
(~>) = tParam rotR
fast :: Pattern Time -> Pattern a -> Pattern a
fast = tParam _fast
fastSqueeze :: Pattern Time -> Pattern a -> Pattern a
fastSqueeze = tParamSqueeze _fast
density :: Pattern Time -> Pattern a -> Pattern a
density = fast
_fast :: Time -> Pattern a -> Pattern a
_fast r p | r == 0 = silence
| r < 0 = rev $ _fast (0-r) p
| otherwise = withResultTime (/ r) $ withQueryTime (* r) p
slow :: Pattern Time -> Pattern a -> Pattern a
slow = tParam _slow
_slow :: Time -> Pattern a -> Pattern a
_slow r p = _fast (1/r) p
slowSqueeze :: Pattern Time -> Pattern a -> Pattern a
slowSqueeze = tParamSqueeze _slow
sparsity :: Pattern Time -> Pattern a -> Pattern a
sparsity = slow
rev :: Pattern a -> Pattern a
rev p = splitQueries $ p {query = \st -> map makeWholeAbsolute $ mapParts (mirrorArc (midCycle $ arc st)) $ map makeWholeRelative (query p st {arc = (mirrorArc (midCycle $ arc st) (arc st))})}
where makeWholeRelative (((s,e), part@(s',e')), v) = (((s'-s, e-e'), part), v)
makeWholeAbsolute (((s,e), part@(s',e')), v) = (((s'-e, e'+s), part), v)
midCycle (s,_) = (sam s) + 0.5
mapParts f es = map (mapFst (mapSnd f)) es
mirrorArc :: Time -> Arc -> Arc
mirrorArc mid' (s, e) = (mid' - (e-mid'), mid'+(mid'-s))
zoom :: Arc -> Pattern a -> Pattern a
zoom (s,e) p = splitQueries $ withResultArc (mapCycle ((/d) . (subtract s))) $ withQueryArc (mapCycle ((+s) . (*d))) p
where d = e-s
fastGap :: Pattern Time -> Pattern a -> Pattern a
fastGap = tParam _fastGap
densityGap = fastGap
compress :: Arc -> Pattern a -> Pattern a
compress = __compress
compressTo :: Arc -> Pattern a -> Pattern a
compressTo = __compressTo
repeatCycles :: Int -> Pattern a -> Pattern a
repeatCycles n p = fastcat (replicate n p)
every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
every tp f p = tp >>= \t -> _every t f p
_every :: Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
_every 0 _ p = p
_every n f p = when ((== 0) . (`mod` n)) f p
every' :: Pattern Int -> Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
every' np op f p = do { n <- np; o <- op; _every' n o f p }
_every' :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
_every' n o f = when ((== o) . (`mod` n)) f
foldEvery :: [Int] -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
foldEvery ns f p = foldr ($) p (map (\x -> _every x f) ns)
when :: (Int -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
when test f p = splitQueries $ p {query = apply}
where apply st | test (floor $ fst $ arc st) = query (f p) st
| otherwise = query p st
whenT :: (Time -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
whenT test f p = splitQueries $ p {query = apply}
where apply st | test (fst $ arc st) = query (f p) st
| otherwise = query p st
cI :: String -> Pattern Int
cI s = Pattern Analog $ \(State a m) -> maybe [] (f a) $ Map.lookup s m
where f a (VI v) = [((a,a),v)]
f a (VF v) = [((a,a),floor v)]
f a (VS v) = maybe [] (\v' -> [((a,a),v')]) (readMaybe v)
cF :: String -> Pattern Double
cF s = Pattern Analog $ \(State a m) -> maybe [] (f a) $ Map.lookup s m
where f a (VI v) = [((a,a),fromIntegral v)]
f a (VF v) = [((a,a),v)]
f a (VS v) = maybe [] (\v' -> [((a,a),v')]) (readMaybe v)
cT = (toRational <$>) . cF
cR = cT
cS :: String -> Pattern String
cS s = Pattern Analog $ \(State a m) -> maybe [] (f a) $ Map.lookup s m
where f a (VI v) = [((a,a),show v)]
f a (VF v) = [((a,a),show v)]
f a (VS v) = [((a,a),v)]