-- | Infinte list @SC3@ pattern functions. module Sound.SC3.Lang.Pattern.Stream where import Data.List {- base -} import Data.Maybe {- base -} import System.Random {- random -} import qualified Sound.SC3 as S {- hsc3 -} import Sound.SC3.Lang.Core {- hsc3-lang -} import qualified Sound.SC3.Lang.Math as M {- hsc3-lang -} import qualified Sound.SC3.Lang.Random.Gen as R -- | Remove successive duplicates. -- -- > rsd [1,2,3,1,2,3] == [1,2,3,1,2,3] rsd :: (Eq a) => [a] -> [a] rsd = let f (p,_) i = (Just i,if Just i == p then Nothing else Just i) in mapMaybe snd . scanl f (Nothing,Nothing) -- | True if /a/ is initially equal to /b/. iEq :: Eq a => [a] -> [a] -> Bool iEq = flip isPrefixOf -- | Take elements from /l/ until all elements in /s/ have been seen. -- If /s/ contains duplicate elements these must be seen multiple -- times. -- -- > take_until_forms_set "abc" "a random sentence beginning" == "a random sentence b" take_until_forms_set :: Eq a => [a] -> [a] -> [a] take_until_forms_set s l = if null s then [] else case l of [] -> [] e:l' -> e : take_until_forms_set (delete e s) l' -- | Underlying 'brown'. brown_ :: (RandomGen g,Random n,Num n,Ord n) => (n,n,n) -> (n,g) -> (n,g) brown_ (l,r,s) (n,g) = let (i,g') = randomR (-s,s) g in (S.foldToRange l r (n + i),g') -- | Brown noise with list inputs. -- -- > let l = brown 'α' (repeat 1) (repeat 700) (cycle [1,20]) -- > in l `iEq` [415,419,420,428] brown :: (Enum e,Random n,Num n,Ord n) => e -> [n] -> [n] -> [n] -> [n] brown e l_ r_ s_ = let i = (randomR (head l_,head r_) (mkStdGen (fromEnum e))) rec (n,g) z = case z of [] -> [] (l,r,s):z' -> let (n',g') = brown_ (l,r,s) (n,g) in n' : rec (n',g') z' in rec i (zip3 l_ r_ s_) -- | 'M.exprange' of 'white' exprand :: (Enum e,Random a,Floating a) => e -> a -> a -> [a] exprand e l r = fmap (M.exprange l r) (white e 0 1) -- | Geometric series. -- -- > geom 3 6 `iEq` [3,18,108,648,3888,23328,139968] geom :: Num a => a -> a -> [a] geom i s = iterate (* s) i -- > lace [[0],[1,2],[3,4,5]] `iEq` [0,1,3,0,2,4,0,1,5] -- > lace [[1],[2,5],[3,6]] `iEq` [1,2,3,1,5,6] -- > lace [[1],[2,5],[3,6..]] `iEq` [1,2,3,1,5,6,1,2,9,1,5,12] lace :: [[a]] -> [a] lace = concat . transpose . map cycle -- | Random elements from list. -- -- > take_until_forms_set "string" (rand 'α' "string") == "grtrsiirn" rand :: Enum e => e -> [a] -> [a] rand e a = let k = length a - 1 in map (a !!) (white e 0 k) -- | List section with /wrapped/ indices. -- -- > segment [0..4] 5 (3,5) == [3,4,0] segment :: [a] -> Int -> (Int,Int) -> [a] segment a k (l,r) = let i = map (S.genericWrap 0 (k - 1)) [l .. r] in map (a !!) i -- > slide [1,2,3,4] 4 1 0 True `iEq` [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3]] -- > slide [1,2,3,4,5] 3 (-1) 0 True `iEq` [[1,2,3],[5,1,2],[4,5,1],[3,4,5],[2,3,4]] slide :: [a] -> Int -> Int -> Int -> Bool -> [[a]] slide a j s i wr = let k = length a l = enumFromThen i (i + s) r = map (+ (j - 1)) l in if wr then map (segment a k) (zip l r) else error "slide: non-wrap variant not implemented" -- | 'concat' of 'slide'. slidec :: [a] -> Int -> Int -> Int -> Bool -> [a] slidec = concat .:::: slide -- | White noise. -- -- > take_until_forms_set [1..5] (white 'α' 1 5) == [4,1,2,2,2,1,2,1,2,5,1,4,3] white :: (Random n,Enum e) => e -> n -> n -> [n] white e l r = randomRs (l,r) (mkStdGen (fromEnum e)) -- | Weighted selection of elements from a list. wrand_generic :: (Enum e,Fractional n,Ord n,Random n) => e -> [a] -> [n] -> [a] wrand_generic e a w = let f g = let (r,g') = R.wchoose a w g in r : f g' in if length a /= length w then error "wrand_generic: a/w must be of equal length" else f (mkStdGen (fromEnum e)) -- | Type restricted variant. -- -- > import qualified Sound.SC3.Lang.Collection as C -- -- > let {w = C.normalizeSum [1..5] -- > ;r = wrand 'ζ' "wrand" w} -- > in take_until_forms_set "wrand" r == "dnanrdnaddrnrrndrrdw" wrand :: Enum e => e -> [a] -> [Double] -> [a] wrand = wrand_generic -- | Select elements from /l/ in random sequence, but do not immediately repeat an element. -- -- > take_until_forms_set "string" (xrand 'α' "string") == "grtrsirn" xrand :: Enum e => e -> [a] -> [a] xrand e a = let g = mkStdGen (fromEnum e) k = length a - 1 r = rsd (randomRs (0,k) g) in map (a !!) r