-- | Multiple channel expansion
module Sound.Sc3.Ugen.Mce where

import Control.Monad {- base -}
import Data.List {- base -}

import qualified Data.List.Split as Split {- split -}

import Sound.Sc3.Common.Uid {- hsc3 -}
import qualified Sound.Sc3.Ugen.Math as Math {- hsc3 -}
import Sound.Sc3.Ugen.Ugen {- hsc3 -}

-- | Construct a list of Ugens by applying f to consecutive identifiers (from z) and indices (from 0).
listFillId :: (Integral n, ID z, Enum z) => z -> Int -> (z -> n -> Ugen) -> [Ugen]
listFillId :: forall n z.
(Integral n, ID z, Enum z) =>
z -> Int -> (z -> n -> Ugen) -> [Ugen]
listFillId z
z Int
n z -> n -> Ugen
f = (z -> n -> Ugen) -> [z] -> [n] -> [Ugen]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith z -> n -> Ugen
f [z
z ..] [n
0 .. Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n n -> n -> n
forall a. Num a => a -> a -> a
- n
1]

-- | Construct a list of Ugens by applying f at consecutive indices (from 0).
listFillM :: (Uid m, Integral n) => Int -> (n -> m Ugen) -> m [Ugen]
listFillM :: forall (m :: * -> *) n.
(Uid m, Integral n) =>
Int -> (n -> m Ugen) -> m [Ugen]
listFillM Int
n n -> m Ugen
f = (n -> m Ugen) -> [n] -> m [Ugen]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM n -> m Ugen
f [n
0 .. Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n n -> n -> n
forall a. Num a => a -> a -> a
- n
1]

-- | Construct a list of Ugens by applying f at consecutive indices (from 0).
listFill :: Integral n => Int -> (n -> Ugen) -> [Ugen]
listFill :: forall n. Integral n => Int -> (n -> Ugen) -> [Ugen]
listFill Int
n n -> Ugen
f = (n -> Ugen) -> [n] -> [Ugen]
forall a b. (a -> b) -> [a] -> [b]
map n -> Ugen
f [n
0 .. Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n n -> n -> n
forall a. Num a => a -> a -> a
- n
1]

-- | 'mce' of 'replicate'
mceConst :: Int -> Ugen -> Ugen
mceConst :: Int -> Ugen -> Ugen
mceConst Int
n = [Ugen] -> Ugen
mce ([Ugen] -> Ugen) -> (Ugen -> [Ugen]) -> Ugen -> Ugen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Ugen -> [Ugen]
forall a. Int -> a -> [a]
replicate Int
n

-- | 'mce' of 'map' /f/ of 'id_seq' /n/.
mceGenId :: ID z => (Id -> Ugen) -> Int -> z -> Ugen
mceGenId :: forall z. ID z => (Int -> Ugen) -> Int -> z -> Ugen
mceGenId Int -> Ugen
f Int
n = [Ugen] -> Ugen
mce ([Ugen] -> Ugen) -> (z -> [Ugen]) -> z -> Ugen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Ugen) -> [Int] -> [Ugen]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Ugen
f ([Int] -> [Ugen]) -> (z -> [Int]) -> z -> [Ugen]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> z -> [Int]
forall a. ID a => Int -> a -> [Int]
id_seq Int
n

-- | Applicative variant of mceGenId.
mceGenM :: Applicative f => f Ugen -> Int -> f Ugen
mceGenM :: forall (f :: * -> *). Applicative f => f Ugen -> Int -> f Ugen
mceGenM f Ugen
f Int
n = ([Ugen] -> Ugen) -> f [Ugen] -> f Ugen
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Ugen] -> Ugen
mce (Int -> f Ugen -> f [Ugen]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
n f Ugen
f)

-- | Count 'mce' channels.
mceSize :: Ugen -> Ugen
mceSize :: Ugen -> Ugen
mceSize = Int -> Ugen
forall n. Real n => n -> Ugen
constant (Int -> Ugen) -> (Ugen -> Int) -> Ugen -> Ugen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Ugen] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Ugen] -> Int) -> (Ugen -> [Ugen]) -> Ugen -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ugen -> [Ugen]
mceChannels

-- | Mix divided by number of inputs.
mceMean :: Ugen -> Ugen
mceMean :: Ugen -> Ugen
mceMean Ugen
e = let p :: [Ugen]
p = Ugen -> [Ugen]
mceChannels Ugen
e in [Ugen] -> Ugen
Math.sum_opt [Ugen]
p Ugen -> Ugen -> Ugen
forall a. Fractional a => a -> a -> a
/ Int -> Ugen
forall n. Real n => n -> Ugen
constant ([Ugen] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Ugen]
p)

-- | Construct an Mce array of Ugens.
mceFill :: Integral n => Int -> (n -> Ugen) -> Ugen
mceFill :: forall n. Integral n => Int -> (n -> Ugen) -> Ugen
mceFill Int
n = [Ugen] -> Ugen
mce ([Ugen] -> Ugen) -> ((n -> Ugen) -> [Ugen]) -> (n -> Ugen) -> Ugen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> (n -> Ugen) -> [Ugen]
forall n. Integral n => Int -> (n -> Ugen) -> [Ugen]
listFill Int
n

-- | 'mce' of 'listFillId'
mceFillId :: (Integral n, ID z, Enum z) => z -> Int -> (z -> n -> Ugen) -> Ugen
mceFillId :: forall n z.
(Integral n, ID z, Enum z) =>
z -> Int -> (z -> n -> Ugen) -> Ugen
mceFillId z
z Int
n = [Ugen] -> Ugen
mce ([Ugen] -> Ugen)
-> ((z -> n -> Ugen) -> [Ugen]) -> (z -> n -> Ugen) -> Ugen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. z -> Int -> (z -> n -> Ugen) -> [Ugen]
forall n z.
(Integral n, ID z, Enum z) =>
z -> Int -> (z -> n -> Ugen) -> [Ugen]
listFillId z
z Int
n

-- | Type specialised mceFill
mceFillInt :: Int -> (Int -> Ugen) -> Ugen
mceFillInt :: Int -> (Int -> Ugen) -> Ugen
mceFillInt = Int -> (Int -> Ugen) -> Ugen
forall n. Integral n => Int -> (n -> Ugen) -> Ugen
mceFill

-- | Collapse possible mce by summing.
mix :: Ugen -> Ugen
mix :: Ugen -> Ugen
mix = [Ugen] -> Ugen
Math.sum_opt ([Ugen] -> Ugen) -> (Ugen -> [Ugen]) -> Ugen -> Ugen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ugen -> [Ugen]
mceChannels

-- | Mix variant, sum to n channels.
mixTo :: Int -> Ugen -> Ugen
mixTo :: Int -> Ugen -> Ugen
mixTo Int
n Ugen
u =
  let xs :: [[Ugen]]
xs = [[Ugen]] -> [[Ugen]]
forall a. [[a]] -> [[a]]
transpose (Int -> [Ugen] -> [[Ugen]]
forall e. Int -> [e] -> [[e]]
Split.chunksOf Int
n (Ugen -> [Ugen]
mceChannels Ugen
u))
  in [Ugen] -> Ugen
mce (([Ugen] -> Ugen) -> [[Ugen]] -> [Ugen]
forall a b. (a -> b) -> [a] -> [b]
map [Ugen] -> Ugen
Math.sum_opt [[Ugen]]
xs)

-- | 'mix' of 'mceFill'
mixFill :: Integral n => Int -> (n -> Ugen) -> Ugen
mixFill :: forall n. Integral n => Int -> (n -> Ugen) -> Ugen
mixFill Int
n = Ugen -> Ugen
mix (Ugen -> Ugen) -> ((n -> Ugen) -> Ugen) -> (n -> Ugen) -> Ugen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> (n -> Ugen) -> Ugen
forall n. Integral n => Int -> (n -> Ugen) -> Ugen
mceFill Int
n

-- | Type specialised mixFill
mixFillInt :: Int -> (Int -> Ugen) -> Ugen
mixFillInt :: Int -> (Int -> Ugen) -> Ugen
mixFillInt = Int -> (Int -> Ugen) -> Ugen
forall n. Integral n => Int -> (n -> Ugen) -> Ugen
mixFill

-- | Type specialised mixFill
mixFillUgen :: Int -> (Ugen -> Ugen) -> Ugen
mixFillUgen :: Int -> (Ugen -> Ugen) -> Ugen
mixFillUgen = Int -> (Ugen -> Ugen) -> Ugen
forall n. Integral n => Int -> (n -> Ugen) -> Ugen
mixFill

-- | 'mix' of 'mceFillId'
mixFillId :: (Integral n, ID z, Enum z) => z -> Int -> (z -> n -> Ugen) -> Ugen
mixFillId :: forall n z.
(Integral n, ID z, Enum z) =>
z -> Int -> (z -> n -> Ugen) -> Ugen
mixFillId z
z Int
n = Ugen -> Ugen
mix (Ugen -> Ugen)
-> ((z -> n -> Ugen) -> Ugen) -> (z -> n -> Ugen) -> Ugen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. z -> Int -> (z -> n -> Ugen) -> Ugen
forall n z.
(Integral n, ID z, Enum z) =>
z -> Int -> (z -> n -> Ugen) -> Ugen
mceFillId z
z Int
n

-- | Monad variant on mixFill.
mixFillM :: (Integral n, Monad m) => Int -> (n -> m Ugen) -> m Ugen
mixFillM :: forall n (m :: * -> *).
(Integral n, Monad m) =>
Int -> (n -> m Ugen) -> m Ugen
mixFillM Int
n n -> m Ugen
f = ([Ugen] -> Ugen) -> m [Ugen] -> m Ugen
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Ugen] -> Ugen
Math.sum_opt ((n -> m Ugen) -> [n] -> m [Ugen]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM n -> m Ugen
f [n
0 .. Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n n -> n -> n
forall a. Num a => a -> a -> a
- n
1])