zwirn-core-0.1.1.0: src/Zwirn/Core/Cord.hs
{-# LANGUAGE FlexibleInstances #-}
module Zwirn.Core.Cord where
{-
Cord.hs - functions on parallel signals
Copyright (C) 2025, Martin Gius
This library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library. If not, see <http://www.gnu.org/licenses/>.
-}
import Control.Monad (join)
import Data.Bifunctor (first, second)
import Zwirn.Core.Core
import Zwirn.Core.Query
import Zwirn.Core.Random
import Zwirn.Core.Time
import Zwirn.Core.Tree
import Zwirn.Core.Types
type Cord = ZwirnT Tree
liftList :: ([Tree (Value i a, st)] -> [Tree (Value i b, st)]) -> Cord st i a -> Cord st i b
liftList f = withInner g
where
g (Leaf x) = Branch $ f [Leaf x]
g (Branch xs) = Branch $ f xs
liftListWithTimeState :: (Time -> st -> [Tree (Value i a, st)] -> [Tree (Value i b, st)]) -> Cord st i a -> Cord st i b
liftListWithTimeState f = withInnerTimeState g
where
g t st (Leaf x) = Branch $ f t st [Leaf x]
g t st (Branch xs) = Branch $ f t st xs
instance HasSilence Tree where
silence = zwirn $ const $ const $ Branch []
-- | get the current depth of the cord
depth :: Cord st i a -> Cord st i Int
depth = withInner (\t -> first (fmap (const $ topLength t)) <$> t)
-- | group a list of cords
stack :: [Cord st i a] -> Cord st i a
stack zs = zwirn $ \t st -> Branch $ map (\x -> unzwirn x t st) zs
-- | project cord on specific index
project :: Cord st i Int -> Cord st i a -> Cord st i a
project i x = withInner . look <$> i <$$> x
-- | layer functions over an input
layer :: Cord st i (Cord st i a -> Cord st i b) -> Cord st i a -> Cord st i b
layer fs x = zwirn q
where
q t st = squeezeJoin $ (\c -> unzwirn c t st) . ($ x) . value . fst <$> unzwirn fs t st
-- | insert cord a specific index
insert :: Cord st i Int -> Cord st i a -> Cord st i a -> Cord st i a
insert ic x y = (($ y) . ($ x)) . insert' =<< ic
where
insert' :: Int -> Cord st i a -> Cord st i a -> Cord st i a
insert' i x ys = zwirn $ \t st -> insertT i (unzwirn x t st) (unzwirn ys t st)
-- | remove cord at specific index
remove :: Cord st i Int -> Cord st i a -> Cord st i a
remove i x = withInner . removeT <$> i <$$> x
-- | apply function to specific index
at :: Cord st i Int -> Cord st i (Cord st i a -> Cord st i a) -> Cord st i a -> Cord st i a
at i f x = insert i (innerApply f $ project i x) (remove i x)
arp :: Cord st i a -> Cord st i a
arp = withInner trans
where
trans :: Tree (Value i a, st) -> Tree (Value i a, st)
trans (Leaf x) = Leaf x
trans (Branch []) = Branch []
trans (Branch xs) = Branch $ map (\i -> shif (length xs) i (xs !! i)) [0 .. length xs - 1]
where
shif :: Int -> Int -> Tree (Value i a, st) -> Tree (Value i a, st)
shif total i x = first (\v -> v {time = time v - fromIntegral i / fromIntegral total}) <$> x
reverseC :: Cord st i a -> Cord st i a
reverseC = liftList reverse
rotateC :: Cord st i a -> Cord st i a
rotateC = liftList rotateList
where
rotateList (x : xs) = xs ++ [x]
invertC :: (Num a) => Cord st i a -> Cord st i a
invertC = liftList invertList
where
invertList (x : xs) = xs ++ [fmap (first $ fmap (+ 12)) x]
enumFromToStack :: (Ord a, Num a) => Cord st i a -> Cord st i a -> Cord st i a
enumFromToStack xz yz = join $ en <$> xz <*> yz
where
en x y = stack $ map pure $ enumerateFromTo x y
enumFromThenToStack :: (Ord a, Num a) => Cord st i a -> Cord st i a -> Cord st i a -> Cord st i a
enumFromThenToStack xz yz zz = join $ en <$> xz <*> yz <*> zz
where
en x y z = stack $ map pure $ enumerateFromThenTo x y z