{-# OPTIONS_GHC -fno-warn-orphans #-} {-# Language TypeFamilies, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} module Csound.SigSpace( SigSpace(..), BindSig(..), mul, on, uon, At(..), mixAt, bat, cfd, cfd4, cfds, cfdSpec, cfdSpec4, cfdsSpec, wsum ) where import Control.Monad import Control.Applicative import Csound.Typed import Csound.Types import Csound.Typed.Opcode(pvscross, pvscale, pvsmix, balance) -- | A class for easy way to process the outputs of the instruments. class SigSpace a where mapSig :: (Sig -> Sig) -> a -> a -- | A class for easy way to process the outputs of the instruments. class SigSpace a => BindSig a where bindSig :: (Sig -> SE Sig) -> a -> SE a -- | Scaling the sound. mul :: SigSpace a => Sig -> a -> a mul k = mapSig (k * ) -- rescaling -- | Rescaling of the bipolar signal (-1, 1) -> (a, b) -- -- > on a b biSig on :: SigSpace a => Sig -> Sig -> a -> a on a b x = uon a b $ mapSig unipolar x where unipolar a = 0.5 + 0.5 * a -- | Rescaling of the unipolar signal (0, 1) -> (a, b) -- -- > on a b uniSig uon :: SigSpace a => Sig -> Sig -> a -> a uon a b = mapSig (\x -> a + (b - a) * x) -- | Crossfade. -- -- > cfd coeff sig1 sig2 -- -- If coeff equals 0 then we get the first signal and if it equals 1 we get the second signal. cfd :: (Num a, SigSpace a) => Sig -> a -> a -> a cfd coeff a b = (1 - coeff) `mul` a + coeff `mul` b genCfds :: a -> (Sig -> a -> a -> a) -> [Sig] -> [a] -> a genCfds zero mixFun cs xs = case xs of [] -> zero a:as -> foldl (\x f -> f x) a $ zipWith mix' cs as where mix' c a b = mixFun c b a -- | Bilinear interpolation for four signals. -- The signals are placed in the corners of the unit square. -- The first two signals are the xy coordinates in the square. -- -- > cfd4 x y a b c d -- -- * (0, 0) is for a -- -- * (1, 0) is for b -- -- * (1, 1) is for c -- -- * (0, 1) is for d cfd4 :: (Num a, SigSpace a) => Sig -> Sig -> a -> a -> a -> a -> a cfd4 x y a b c d = sum $ zipWith mul [(1 - x) * (1 - y), x * (1 - y) , x * y, (1 - x) * y] [a, b, c, d] -- | Generic crossfade for n coefficients and n+1 signals. -- -- > cfds coeffs sigs cfds :: (Num a, SigSpace a) => [Sig] -> [a] -> a cfds = genCfds 0 cfd -- | Spectral crossfade. cfdSpec :: Sig -> Spec -> Spec -> Spec cfdSpec coeff a b = pvscross a b (1 - coeff) coeff -- | Spectral bilinear crossfade (see @cfd4@). cfdSpec4 :: Sig -> Sig -> Spec -> Spec -> Spec -> Spec -> Spec cfdSpec4 x y a b c d = foldl1 pvsmix [ pvscale a ((1 - x) * (1 - y)) , pvscale b (x * (1 - y)) , pvscale c (x * y) , pvscale d ((1 - x) * y) ] -- | Generic spectral crossfade. cfdsSpec :: [Sig] -> [Spec] -> Spec cfdsSpec = genCfds undefined cfdSpec -- | Weighted sum. wsum :: (Num a, SigSpace a) => [(Sig, a)] -> a wsum = sum . fmap (uncurry mul) instance SigSpace Sig where mapSig = id instance BindSig Sig where bindSig = id instance SigSpace (Sig, Sig) where mapSig f (a1, a2) = (f a1, f a2) instance BindSig (Sig, Sig) where bindSig f (a1, a2) = (,) <$> f a1 <*> f a2 instance SigSpace (Sig, Sig, Sig) where mapSig f (a1, a2, a3) = (f a1, f a2, f a3) instance BindSig (Sig, Sig, Sig) where bindSig f (a1, a2, a3) = (,,) <$> f a1 <*> f a2 <*> f a3 instance SigSpace (Sig, Sig, Sig, Sig) where mapSig f (a1, a2, a3, a4) = (f a1, f a2, f a3, f a4) instance BindSig (Sig, Sig, Sig, Sig) where bindSig f (a1, a2, a3, a4) = (,,,) <$> f a1 <*> f a2 <*> f a3 <*> f a4 instance SigSpace (SE Sig) where mapSig f = fmap (mapSig f) instance BindSig (SE Sig) where bindSig f = fmap (bindSig f) instance SigSpace (SE (Sig, Sig)) where mapSig f = fmap (mapSig f) instance BindSig (SE (Sig, Sig)) where bindSig f = fmap (bindSig f) instance SigSpace (SE (Sig, Sig, Sig)) where mapSig f = fmap (mapSig f) instance BindSig (SE (Sig, Sig, Sig)) where bindSig f = fmap (bindSig f) instance SigSpace (SE (Sig, Sig, Sig, Sig)) where mapSig f = fmap (mapSig f) instance BindSig (SE (Sig, Sig, Sig, Sig)) where bindSig f = fmap (bindSig f) ----------------------------------------------------- -- numeric instances -- Num instance Num (SE Sig) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (SE (Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (SE (Sig, Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (SE (Sig, Sig, Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (a -> Sig) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (a -> (Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (a -> (Sig, Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (a -> (Sig, Sig, Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (a -> SE Sig) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (a -> SE (Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (a -> SE (Sig, Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs instance Num (a -> SE (Sig, Sig, Sig, Sig)) where (+) = liftA2 (+) (*) = liftA2 (*) negate = fmap negate fromInteger = return . fromInteger signum = fmap signum abs = fmap abs -- Fractional instance Fractional (Sig, Sig) where (a1, a2) / (b1, b2) = (a1 / b1, a2 / b2) fromRational a = (fromRational a, fromRational a) instance Fractional (Sig, Sig, Sig) where (a1, a2, a3) / (b1, b2, b3) = (a1 / b1, a2 / b2, a3 / b3) fromRational a = (fromRational a, fromRational a, fromRational a) instance Fractional (Sig, Sig, Sig, Sig) where (a1, a2, a3, a4) / (b1, b2, b3, b4) = (a1 / b1, a2 / b2, a3 / b3, a4 / b4) fromRational a = (fromRational a, fromRational a, fromRational a, fromRational a) instance Fractional (SE Sig) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (SE (Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (SE (Sig, Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (SE (Sig, Sig, Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (a -> SE Sig) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (a -> SE (Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (a -> SE (Sig, Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (a -> SE (Sig, Sig, Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (a -> Sig) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (a -> (Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (a -> (Sig, Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational instance Fractional (a -> (Sig, Sig, Sig, Sig)) where (/) = liftA2 (/) fromRational = return . fromRational ----------------------------------------------------------------------- ----------------------------------------------------------------------- class SigSpace b => At a b c where type AtOut a b c :: * at :: (a -> b) -> c -> AtOut a b c -- | It applies an effect and balances the processed signal by original one. bat :: At Sig a b => (Sig -> a) -> b -> AtOut Sig a b bat f = at (\x -> mapSig ( `balance` x) $ f x) -- | It applies an effect and mixes the processed signal with original one. -- The first argument is for proportion of dry/wet (original/processed). -- It's like @at@ but it allows to balance processed signal with original one. mixAt :: (At a b c, c ~ AtOut a b c, SigSpace c, Num c) => Sig -> (a -> b) -> c -> c mixAt k f a = cfd k a (at f a) instance SigSpace a => At Sig Sig a where type AtOut Sig Sig a = a at f a = mapSig f a ------------------------------------------------------ -- for (Sig -> SE Sig) instance At Sig (SE Sig) Sig where type AtOut Sig (SE Sig) Sig = SE Sig at f a = f a instance At Sig (SE Sig) Sig2 where type AtOut Sig (SE Sig) Sig2 = SE Sig2 at f a = bindSig f a instance At Sig (SE Sig) Sig3 where type AtOut Sig (SE Sig) Sig3 = SE Sig3 at f a = bindSig f a instance At Sig (SE Sig) Sig4 where type AtOut Sig (SE Sig) Sig4 = SE Sig4 at f a = bindSig f a instance At Sig (SE Sig) (SE Sig) where type AtOut Sig (SE Sig) (SE Sig) = SE Sig at f a = join $ bindSig f a instance At Sig (SE Sig) (SE Sig2) where type AtOut Sig (SE Sig) (SE Sig2) = SE Sig2 at f a = join $ bindSig f a instance At Sig (SE Sig) (SE Sig3) where type AtOut Sig (SE Sig) (SE Sig3) = SE Sig3 at f a = join $ bindSig f a instance At Sig (SE Sig) (SE Sig4) where type AtOut Sig (SE Sig) (SE Sig4) = SE Sig4 at f a = join $ bindSig f a ----------------------------------------------------- -- mono to stereo instance At Sig Sig2 Sig where type AtOut Sig Sig2 Sig = Sig2 at f a = f a instance At Sig Sig2 (SE Sig) where type AtOut Sig Sig2 (SE Sig) = SE Sig2 at f a = fmap f a instance At Sig Sig2 Sig2 where type AtOut Sig Sig2 Sig2 = Sig2 at f a = 0.5 * (f (fst a) + f (snd a)) instance At Sig Sig2 (SE Sig2) where type AtOut Sig Sig2 (SE Sig2) = SE Sig2 at f a = fmap (at f) a --------------------------------------------------------- --------------------------------------------------------- -- Sig2 -> Sig2 fromMono a = (a, a) instance At Sig2 Sig2 Sig where type AtOut Sig2 Sig2 Sig = Sig2 at f a = f $ fromMono a instance At Sig2 Sig2 Sig2 where type AtOut Sig2 Sig2 Sig2 = Sig2 at f a = f a instance At Sig2 Sig2 (SE Sig) where type AtOut Sig2 Sig2 (SE Sig) = SE Sig2 at f a = fmap (f . fromMono) a instance At Sig2 Sig2 (SE Sig2) where type AtOut Sig2 Sig2 (SE Sig2) = SE Sig2 at f a = fmap f a --------------------------------------------- -- Sig2 -> SE Sig2 instance At Sig2 (SE Sig2) Sig where type AtOut Sig2 (SE Sig2) Sig = SE Sig2 at f a = f $ fromMono a instance At Sig2 (SE Sig2) Sig2 where type AtOut Sig2 (SE Sig2) Sig2 = SE Sig2 at f a = f a instance At Sig2 (SE Sig2) (SE Sig) where type AtOut Sig2 (SE Sig2) (SE Sig) = SE Sig2 at f a = (f . fromMono) =<< a instance At Sig2 (SE Sig2) (SE Sig2) where type AtOut Sig2 (SE Sig2) (SE Sig2) = SE Sig2 at f a = f =<< a ---------------------------------------------------------