-- | 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 = forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith z -> n -> Ugen
f [z
z..] [n
0 .. forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
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 = forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM n -> m Ugen
f [n
0 .. forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
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 = forall a b. (a -> b) -> [a] -> [b]
map n -> Ugen
f [n
0 .. forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Int -> Ugen
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Ugen] -> Ugen
mce (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 = forall n. Real n => n -> Ugen
constant forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Int
length 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 forall a. Fractional a => a -> a -> a
/ forall n. Real n => n -> Ugen
constant (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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = 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 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 = forall a. [[a]] -> [[a]]
transpose (forall e. Int -> [e] -> [[e]]
Split.chunksOf Int
n (Ugen -> [Ugen]
mceChannels Ugen
u))
    in [Ugen] -> Ugen
mce (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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = forall n. Integral n => Int -> (n -> Ugen) -> Ugen
mixFill

-- | Type specialised mixFill
mixFillUgen :: Int -> (Ugen -> Ugen) -> Ugen
mixFillUgen :: Int -> (Ugen -> Ugen) -> Ugen
mixFillUgen = 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 forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Ugen] -> Ugen
Math.sum_opt (forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM n -> m Ugen
f [n
0 .. forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n forall a. Num a => a -> a -> a
- n
1])