module Csound.Sam (
Sample, Sam, Bpm, runSam,
mapBpm, bindSam, bindBpm, liftSam,
sig1, sig2, infSig1, infSig2, fromSig1, fromSig2, rest,
wav, wavr, seg, segr, rndWav, rndWavr, rndSeg, rndSegr, ramWav,
wav1, wavr1, seg1, segr1, rndWav1, rndWavr1, rndSeg1, rndSegr1, ramWav1,
linEnv, expEnv, hatEnv, decEnv, riseEnv, edecEnv, eriseEnv,
del, str, wide, flow, pick, pickBy, lim, atPan, atPch, atCps,
loop, rep1, rep, pat1, pat,
Chord,
arpUp, arpDown, arpOneOf, arpFreqOf,
arpUp1, arpDown1, arpOneOf1, arpFreqOf1,
wall, forAirports, genForAirports
) where
import Control.Monad.Trans.Class
import Control.Applicative
import Control.Monad.Trans.Reader
import Csound.Base
type Sam = Sample Sig2
data Dur = Dur D | InfDur
type Bpm = D
newtype Sample a = Sam { unSam :: ReaderT Bpm SE (S a)
} deriving (Functor)
instance Applicative Sample where
pure = Sam . pure . pure
(Sam rf) <*> (Sam ra) = Sam $ liftA2 (<*>) rf ra
data S a = S
{ samSig :: a
, samDur :: Dur
} deriving (Functor)
instance Applicative S where
pure a = S a InfDur
(S f df) <*> (S a da) = S (f a) $ case (df, da) of
(Dur durF, Dur durA) -> Dur $ maxB durF durA
_ -> InfDur
instance Num a => Num (Sample a) where
(+) = liftA2 (+)
(*) = liftA2 (*)
() = liftA2 ()
negate = fmap negate
abs = fmap abs
signum = fmap signum
fromInteger = pure . fromInteger
instance Fractional a => Fractional (Sample a) where
recip = fmap recip
fromRational = pure . fromRational
instance SigSpace a => SigSpace (Sample a) where
mapSig f = fmap (mapSig f)
instance RenderCsd Sam where
renderCsdBy opt sample = renderCsdBy opt (runSam (120 * 4) sample)
liftSam :: Sample (SE a) -> Sample a
liftSam (Sam ra) = Sam $ do
a <- ra
lift $ fmap (\x -> a{ samSig = x}) $ samSig a
mapBpm :: (Bpm -> Sig2 -> Sig2) -> Sam -> Sam
mapBpm f (Sam ra) = Sam $ do
bpm <- ask
a <- ra
return $ a { samSig = f bpm $ samSig a }
bindSam :: (Sig2 -> SE Sig2) -> Sam -> Sam
bindSam f = liftSam . fmap f
bindBpm :: (Bpm -> Sig2 -> SE Sig2) -> Sam -> Sam
bindBpm f (Sam ra) = Sam $ do
bpm <- ask
a <- ra
lift $ fmap (\x -> a{ samSig = x}) $ f bpm $ samSig a
infSig1 :: Sig -> Sam
infSig1 x = pure (x, x)
infSig2 :: Sig2 -> Sam
infSig2 = pure
sig1 :: D -> Sig -> Sam
sig1 dt a = Sam $ reader $ \_ -> S (a, a) (Dur dt)
sig2 :: D -> Sig2 -> Sam
sig2 dt a = Sam $ reader $ \_ -> S a (Dur dt)
fromSig1 :: D -> Sig -> Sam
fromSig1 dt = lim dt . infSig1
fromSig2 :: D -> Sig2 -> Sam
fromSig2 dt = lim dt . infSig2
rest :: D -> Sam
rest dt = Sam $ reader $ \bpm -> S 0 (Dur $ toSec bpm dt)
wav :: String -> Sam
wav fileName = Sam $ return $ S (readSnd fileName) (Dur $ lengthSnd fileName)
wavr :: String -> Sam
wavr fileName = Sam $ return $ S (takeSnd len $ loopWav (1) fileName) (Dur len)
where len = lengthSnd fileName
seg :: D -> D -> String -> Sam
seg start end fileName = Sam $ return $ S (readSegWav start end 1 fileName) (Dur len)
where len = end start
segr :: D -> D -> String -> Sam
segr start end fileName = Sam $ return $ S (readSegWav start end (1) fileName) (Dur len)
where len = end start
rndWav :: D -> String -> Sam
rndWav dt fileName = rndSeg dt 0 (lengthSnd fileName) fileName
rndWavr :: D -> String -> Sam
rndWavr dt fileName = rndSegr dt 0 (lengthSnd fileName) fileName
rndSeg :: D -> D -> D -> String -> Sam
rndSeg = genRndSeg 1
rndSegr :: D -> D -> D -> String -> Sam
rndSegr = genRndSeg (1)
genRndSeg :: Sig -> D -> D -> D -> String -> Sam
genRndSeg speed len start end fileName = Sam $ lift $ do
x <- random 0 1
let a = start + dl * x
let b = a + len
return $ S (readSegWav a b speed fileName) (Dur len)
where dl = end len
ramWav :: LoopMode -> Sig -> String -> Sam
ramWav loopMode speed fileName = Sam $ return $ S (ramSnd loopMode speed fileName) (Dur $ lengthSnd fileName)
ramWav1 :: LoopMode -> Sig -> String -> Sam
ramWav1 loopMode speed fileName = Sam $ return $ S (let x = ramSnd1 loopMode speed fileName in (x, x)) (Dur $ lengthSnd fileName)
wav1 :: String -> Sam
wav1 fileName = Sam $ return $ S (let x = readSnd1 fileName in (x, x)) (Dur $ lengthSnd fileName)
wavr1 :: String -> Sam
wavr1 fileName = Sam $ return $ S (let x = takeSnd len $ loopWav1 (1) fileName in (x, x)) (Dur len)
where len = lengthSnd fileName
seg1 :: D -> D -> String -> Sam
seg1 start end fileName = Sam $ return $ S (let x = readSegWav1 start end 1 fileName in (x, x)) (Dur len)
where len = end start
segr1 :: D -> D -> String -> Sam
segr1 start end fileName = Sam $ return $ S (let x = readSegWav1 start end (1) fileName in (x, x)) (Dur len)
where len = end start
rndWav1 :: D -> String -> Sam
rndWav1 dt fileName = rndSeg1 dt 0 (lengthSnd fileName) fileName
rndWavr1 :: D -> String -> Sam
rndWavr1 dt fileName = rndSegr1 dt 0 (lengthSnd fileName) fileName
rndSeg1 :: D -> D -> D -> String -> Sam
rndSeg1 = genRndSeg1 1
rndSegr1 :: D -> D -> D -> String -> Sam
rndSegr1 = genRndSeg1 (1)
genRndSeg1 :: Sig -> D -> D -> D -> String -> Sam
genRndSeg1 speed len start end fileName = Sam $ lift $ do
x <- random 0 1
let a = start + dl * x
let b = a + len
return $ S (let y = readSegWav1 a b speed fileName in (y, y)) (Dur len)
where dl = end len
toSec :: Bpm -> D -> D
toSec bpm a = a * 60 / bpm
toSecSig :: Bpm -> Sig -> Sig
toSecSig bpm a = a * 60 / sig bpm
runSam :: Bpm -> Sam -> SE Sig2
runSam bpm x = fmap samSig $ runReaderT (unSam x) bpm
addDur :: D -> Dur -> Dur
addDur d x = case x of
Dur a -> Dur $ d + a
InfDur -> InfDur
atPch :: Sig -> Sam -> Sam
atPch k = mapSig (scalePitch k)
atPan :: Sig -> Sam -> Sam
atPan k = fmap (\(a, b) -> pan2 (mean [a, b]) k)
atCps :: Sig -> Sam -> Sam
atCps k = mapSig (scaleSpec k)
tfmBy :: (S Sig2 -> Sig2) -> Sam -> Sam
tfmBy f = Sam . fmap (\x -> x { samSig = f x }) . unSam
tfmS :: (Bpm -> S Sig2 -> S Sig2) -> Sam -> Sam
tfmS f ra = Sam $ do
bpm <- ask
a <- unSam ra
return $ f bpm a
setInfDur :: Sam -> Sam
setInfDur = Sam . fmap (\a -> a { samDur = InfDur }) . unSam
del :: D -> Sam -> Sam
del dt = tfmS phi
where phi bpm x = x { samSig = asig, samDur = dur }
where
absDt = toSec bpm dt
asig = delaySnd absDt $ samSig x
dur = addDur absDt $ samDur x
str :: D -> Sam -> Sam
str k (Sam a) = Sam $ withReaderT ( * k) a
wide :: D -> Sam -> Sam
wide = str . recip
flow :: [Sam] -> Sam
flow [] = 0
flow as = foldr1 flow2 as
flow2 :: Sam -> Sam -> Sam
flow2 (Sam ra) (Sam rb) = Sam $ do
a <- ra
b <- rb
let sa = samSig a
let sb = samSig b
return $ case (samDur a, samDur b) of
(Dur da, Dur db) -> S (sa + delaySnd da sb) (Dur $ da + db)
(InfDur, _) -> a
(Dur da, InfDur) -> S (sa + delaySnd da sb) InfDur
type PickFun = [(D, D)] -> Evt Unit -> Evt (D, D)
genPick :: PickFun -> Sig -> [Sam] -> Sam
genPick pickFun dt as = Sam $ do
bpm <- ask
xs <- sequence $ fmap unSam as
let ds = fmap (getDur . samDur) xs
let sigs = fmap samSig xs
return $ S (sched (\n -> return $ atTuple sigs $ sig n) $ pickFun (zip ds (fmap int [0..])) $ metroS bpm dt) InfDur
where getDur x = case x of
InfDur -> 1
Dur d -> d
pick :: Sig -> [Sam] -> Sam
pick = genPick oneOf
pickBy :: Sig -> [(D, Sam)] -> Sam
pickBy dt as = genPick (\ds -> freqOf $ zip (fmap fst as) ds) dt (fmap snd as)
lim :: D -> Sam -> Sam
lim d = tfmS $ \bpm x ->
let absD = toSec bpm d
in x { samSig = takeSnd absD $ samSig x
, samDur = Dur absD }
type EnvFun = (Dur -> D -> D -> Sig)
genEnv :: EnvFun -> D -> D -> Sam -> Sam
genEnv env start end = tfmS f
where f bpm a = a { samSig = mul (env (samDur a) absStart absEnd) $ samSig a }
where
absStart = toSec bpm start
absEnd = toSec bpm end
linEnv :: D -> D -> Sam -> Sam
linEnv = genEnv f
where f dur start end = case dur of
InfDur -> linseg [0, start, 1]
Dur d -> linseg [0, start, 1, maxB 0 (d start end), 1, end , 0]
expEnv :: D -> D -> Sam -> Sam
expEnv = genEnv f
where
f dur start end = case dur of
InfDur -> expseg [zero, start, 1]
Dur d -> expseg [zero, start, 1, maxB 0 (d start end), 1, end , zero]
zero = 0.00001
genEnv1 :: (D -> Sig) -> Sam -> Sam
genEnv1 envFun = tfmBy f
where
f a = flip mul (samSig a) $ case samDur a of
InfDur -> 1
Dur d -> envFun d
hatEnv :: Sam -> Sam
hatEnv = genEnv1 $ \d -> oscBy (polys 0 1 [0, 1, 1]) (1 / sig d)
riseEnv :: Sam -> Sam
riseEnv = genEnv1 $ \d -> linseg [0, d, 1]
decEnv :: Sam -> Sam
decEnv = genEnv1 $ \d -> linseg [1, d, 0]
eriseEnv :: Sam -> Sam
eriseEnv = genEnv1 $ \d -> expseg [0.0001, d, 1]
edecEnv :: Sam -> Sam
edecEnv = genEnv1 $ \d -> expseg [1, d, 0.0001]
type LoopFun = D -> D -> Sig2 -> Sig2
genLoop :: LoopFun -> Sam -> Sam
genLoop g = setInfDur . tfmS f
where
f bpm a = a { samSig = case samDur a of
InfDur -> samSig a
Dur d -> g bpm d (samSig a)
}
loop :: Sam -> Sam
loop = genLoop $ \_ d asig -> repeatSnd d asig
rep1 :: D -> Sam -> Sam
rep1 = rep . return
pat1 :: D -> Sam -> Sam
pat1 = pat . return
rep :: [D] -> Sam -> Sam
rep dts = genLoop $ \bpm d asig -> trigs (const $ return asig) $ fmap (const $ notes bpm d) $ metroS bpm (sig $ sum dts)
where notes bpm _ = zipWith (\t dt-> (toSec bpm t, toSec bpm dt, unit)) (patDurs dts) dts
pat :: [D] -> Sam -> Sam
pat dts = genLoop $ \bpm d asig -> trigs (const $ return asig) $ fmap (const $ notes bpm d) $ metroS bpm (sig $ sum dts)
where notes bpm d = fmap (\t -> (toSec bpm t, d, unit)) $ patDurs dts
wall :: D -> Sam -> Sam
wall dt a = mean [b, del hdt b]
where
hdt = 0.5 * dt
f = pat1 hdt . hatEnv . lim dt
b = f a
type Chord = [D]
type Arp1Fun = Evt Unit -> Evt D
arpInstr :: Sig2 -> D -> SE Sig2
arpInstr asig k = return $ mapSig (scalePitch (sig k)) asig
patDurs :: [D] -> [D]
patDurs dts = reverse $ snd $ foldl (\(counter, res) a -> (a + counter, counter:res)) (0, []) dts
genArp1 :: Arp1Fun -> Sig -> Sam -> Sam
genArp1 arpFun dt = genLoop $ \bpm d asig ->
sched (arpInstr asig) $ withDur d $ arpFun $ metroS bpm dt
arpUp1 :: Chord -> Sig -> Sam -> Sam
arpUp1 = genArp1 . cycleE
arpDown1 :: Chord -> Sig -> Sam -> Sam
arpDown1 ch = arpUp1 (reverse ch)
arpOneOf1 :: Chord -> Sig -> Sam -> Sam
arpOneOf1 = genArp1 . oneOf
arpFreqOf1 :: [D] -> Chord -> Sig -> Sam -> Sam
arpFreqOf1 freqs ch = genArp1 (freqOf (zip freqs ch))
genArp :: Arp1Fun -> [D] -> Sam -> Sam
genArp arpFun dts = genLoop $ \bpm d asig -> trigs (arpInstr asig) $ fmap (notes bpm d) $ arpFun $ metroS bpm (sig $ sum dts)
where notes bpm d pchScale = fmap (\t -> (toSec bpm t, d, pchScale)) $ patDurs dts
arpUp :: Chord -> [D] -> Sam -> Sam
arpUp = genArp . cycleE
arpDown :: Chord -> [D] -> Sam -> Sam
arpDown ch = arpUp (reverse ch)
arpOneOf :: Chord -> [D] -> Sam -> Sam
arpOneOf = genArp . oneOf
arpFreqOf :: [D] -> Chord -> [D] -> Sam -> Sam
arpFreqOf freqs ch = genArp (freqOf $ zip freqs ch)
metroS :: Bpm -> Sig -> Evt Unit
metroS bpm dt = metroE (recip $ toSecSig bpm dt)
forAirports :: [(D, D, D)] -> Sam -> Sam
forAirports xs sample = mean $ flip fmap xs $
\(delTime, loopTime, note) -> del delTime $ pat [loopTime] (atPch (sig note) sample)
genForAirports :: [(D, D, Sam)] -> Sam
genForAirports xs = mean $ fmap (\(delTime, loopTime, sample) -> del delTime $ pat [loopTime] sample) xs