{-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE NoIncoherentInstances #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE NoUndecidableInstances #-} module Vivid.UGens.Multichannel ( -- * Multichannel > Ambisonics --- biPanB2 --- , decodeB2 --- , panB --- , panB2 --- , rotate2 -- * Multichannel > Panners --- , balance2 --- , linPan2 pan2 --- , pan4 --- , panAz -- See above: -- , rotate2 , splay --- , splayAz -- * Multichannel > Select --- , linSelectX --- , linXFade2 , select --- , selectX --- , selectXFocus --- , xFade2 -- * Multichannel , mix --- , numChannels , addChannels ) where import Vivid.SC.SynthDef.Types (CalculationRate(..)) import Vivid.SynthDef --import Vivid.SynthDef.FromUA import Vivid.UGens.Algebraic import Vivid.UGens.Args import Vivid.UGens.Generators.SingleValue (dc) import Vivid.SynthDef.FromUA import Control.Monad (foldM, zipWithM) import Data.List.Split (chunksOf) --- biPanB2 :: --- biPanB2 = --- decodeB2 :: --- decodeB2 = --- panB :: --- panB = --- panB2 :: --- panB2 = --- rotate2 :: --- rotate2 = --- balance2 :: --- balance2 = --- linPan2 :: --- linPan2 = -- | 'pos' is -1 to 1 -- -- 'level' is \"a control-rate level input\" pan2 :: Args '["in","pos"] '["level"] a => a -> SDBody a [Signal] pan2 = makePolyUGen 2 "Pan2" AR (Vs::Vs '["in","pos","level"]) (level_ (1::Float)) -- return a tuple?: -- no no that's exactly when you run into problems with the foldable shit -- people get a tuple when they expect a list.... --- pan4 :: --- pan4 = --- panAz :: --- panAz = -- | "Spreads [a list] of channels across the stereo field." splay :: ToSig s a => [s] -> SDBody' a [Signal] splay sigsMono = do -- sigs' <- mapM toSig sigs let numChans :: Float numChans = toEnum $ max 2 $ (length::[a]->Int) sigsMono let positions :: [Float] positions = map ((\x->x-1) . (*(2/(numChans-1)))) [0..(numChans-1)] -- note SC has a different calculation for KR: let level = sqrt (recip numChans) sigsStereo <- (\x -> zipWithM x sigsMono positions) $ \sig pos -> pan2 (in_ sig, pos_ pos) -- todo: is the rate correct in ALL cases?: mapM (level ~*) =<< foldM addChannels [] sigsStereo -- | "Spreads [a list] of channels across the stereo field. Optional arguments are spread -- and center, and equal power levelCompensation. The formula for the stereo position -- is: -- -- > ((0 .. (n - 1)) * (2 / (n - 1) - 1) * spread + center --- splay' :: --- splay' = --- splayAz :: --- splayAz = -- Don't implement: the geometry is wrong here and it's been deprecated: -- splayZ :: --- linSelectX :: --- linSelectX = --- linXFade2 :: --- linXFade2 = select :: ToSig s as => s -> [SDBody' as Signal] -> SDBody' as Signal select which array = do which' <- toSig which array' <- mapM toSig array addUGen $ UGen (UGName_S "Select") AR (which' : array') 1 --- selectX :: --- selectX = --- selectXFocus :: --- selectXFocus = --- xFade2 :: --- xFade2 = -- | Mixes down a list of audio rate inputs to one. -- -- This is more efficient than e.g. @foldl1 (~+)@ -- -- If the list is empty this is the same as @dc 0@ mix :: ToSig s a => [s] -> SDBody' a Signal mix [] = dc 0 mix [x] = toSig x mix xs = mix =<< (mapM mix' . chunksOf 4) =<< mapM toSig xs where mix' :: [Signal] -> SDBody' a Signal mix' [] = error "something's broken" mix' [x] = return x mix' [a,b] = a ~+ b mix' ins@[_,_,_] = addUGen $ UGen (UGName_S "Sum3") AR ins 1 mix' ins@[_,_,_,_] = addUGen $ UGen (UGName_S "Sum4") AR ins 1 mix' _ = error "that would be weird" --- numChannels :: --- numChannels = -- | Like 'zipWithM' but if the lists are of different lengths, doesn't shorten the longer one addChannels :: (ToSig s0 a, ToSig s1 a) => [s0] -> [s1] -> SDBody' a [Signal] addChannels [] xs = mapM toSig xs addChannels xs [] = mapM toSig xs addChannels (x:xs) (y:ys) = do foo <- toSig x ~+ toSig y (foo:) <$> addChannels xs ys