{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# Language
TypeFamilies,
TypeSynonymInstances,
FlexibleInstances,
FlexibleContexts #-}
module Csound.Exp.Wrapper(
onE1, onE2, toExp, onExp,
Sig, D, Str, Spec, ToSig(..),
Sig2, Sig3, Sig4, Ksig, Amp, Cps, Iamp, Icps,
Val(..),
str, double, ir, ar, kr, sig,
tfm, pref, prim, p,
noRate, setRate, withRate,
getRates, isMultiOutSignature
) where
import Data.Fix
import Data.Default
import Data.String
import Csound.Exp
type Sig2 = (Sig, Sig)
type Sig3 = (Sig, Sig, Sig)
type Sig4 = (Sig, Sig, Sig, Sig)
-- | An alias for control rate signals (it's used only to clarify that 'Csound.Base.kr' was applied to the signal).
type Ksig = Sig
-- | An alias for amplitude.
type Amp = Sig
-- | An alias for cycles per second.
type Cps = Sig
-- | An alias for amplitude as number.
type Iamp = D
-- | An alias for cycles per second as number.
type Icps = D
-- | Audio or control rate signals.
newtype Sig = Sig { unSig :: E }
-- | Doubles.
newtype D = D { unD :: E }
-- | Strings.
newtype Str = Str { unStr :: E }
-- | Spectrum of the signal (see FFT and Spectral Processing at "Csound.Opcode.Advanced").
newtype Spec = Spec { unSpec :: E }
------------------------------------------------------
-- values
instance IsString Str where
fromString = str
class Val a where
toE :: a -> E
fromE :: E -> a
instance Val E where { toE = id; fromE = id }
instance Val (Exp E) where { toE = noRate; fromE = toExp }
instance Val Sig where { toE = unSig; fromE = Sig }
instance Val D where { toE = unD; fromE = D }
instance Val Str where { toE = unStr; fromE = Str }
instance Val Spec where { toE = unSpec; fromE = Spec }
instance Val Tab where
fromE = TabExp
toE x = case x of
TabExp e -> e
primTab -> (prim . PrimTab . Left) primTab
onE1 :: (Val a, Val b) => (E -> E) -> (a -> b)
onE1 f = fromE . f . toE
onE2 :: (Val a, Val b, Val c) => (E -> E -> E) -> (a -> b -> c)
onE2 f a b = fromE $ f (toE a) (toE b)
toExp :: Val a => a -> Exp E
toExp = ratedExpExp . unFix . toE
-- Lifts transformation of main expression
onExp :: (Exp E -> Exp E) -> E -> E
onExp f x = case unFix x of
a -> Fix $ a{ ratedExpExp = f (ratedExpExp a) }
------------------------------------------------
-- basic constructors
noRate :: Val a => Exp E -> a
noRate = ratedExp Nothing
withRate :: Val a => Rate -> Exp E -> a
withRate r = ratedExp (Just r)
ratedExp :: Val a => Maybe Rate -> Exp E -> a
ratedExp r = fromE . Fix . RatedExp r Nothing
prim :: Val a => Prim -> a
prim = noRate . ExpPrim
pref :: Name -> Signature -> Info
pref name signature = Info name signature Prefix Nothing
tfm :: Val a => Info -> [E] -> a
tfm info args = noRate $ Tfm info $ fmap toPrimOr args
-- variables
p :: Val a => Int -> a
p = prim . P
-- | Converts Haskell's doubles to Csound's doubles
double :: Double -> D
double = prim . PrimDouble
-- | Converts Haskell's strings to Csound's strings
str :: String -> Str
str = prim . PrimString
getRates :: MainExp a -> [Rate]
getRates (Tfm info _) = case infoSignature info of
MultiRate outs _ -> outs
_ -> error "Wrapper.hs:getRates - argument should be multiOut"
getRates _ = error "Wrapper.hs:getRates - argument should be Tfm-expression"
isMultiOutSignature :: Signature -> Bool
isMultiOutSignature x = case x of
MultiRate _ _ -> True
_ -> False
--------------------------------------------
-- signals from primitive types
-- | Values that can be converted to signals.
class ToSig a where
toSig :: a -> Sig
instance ToSig D where
toSig = sig
instance ToSig Sig where
toSig = id
instance ToSig Int where
toSig = sig . double . fromIntegral
instance ToSig Double where
toSig = sig . double
--------------------------------------------
-- rate conversion
setRate :: (Val a, Val b) => Rate -> a -> b
setRate r a = fromE $ Fix $ (\x -> x { ratedExpRate = Just r }) $ unFix $ toE a
-- | Sets rate to audio rate.
ar :: Sig -> Sig
ar = setRate Ar
-- | Sets rate to control rate.
kr :: Sig -> Sig
kr = setRate Kr
-- | Converts signal to double.
ir :: Sig -> D
ir = setRate Ir
-- | Converts numbers to signals. It creates constant signal.
sig :: D -> Sig
sig (D a) = Sig a
--------------------------------------------
-- defaults
instance Default E where def = prim $ PrimDouble 0
instance Default Sig where def = fromE def
instance Default D where def = fromE def
instance Default Tab where def = fromE def
instance Default Spec where def = fromE def
instance Default Str where def = prim $ PrimString ""